环境搭建概述
下面开始手工搭建 PHP 的开发环境、部署环境
测试环境
测试环境的系统参数如下(内容将以最新版为准进行调整
):
系统 : `Debian GNU/Linux 12 (Bookworm) x86_64`
内核 : `linux-image-6.1.0-26-amd64`
系统 : `Debian GNU/Linux 13 (trixie)`
内核 : `linux-image-6.12.41+deb13-amd64`
PHP 环境目录结构
===============================================================================
LNMPP 环境目录
===============================================================================
├─ /server --------------------------------------------------- 服务目录
| ├─ sqlite -------------------------------------- SQLite3基目录
| | └─ ...
| |
| ├─ redis --------------------------------------- redis基目录
| | ├─ redis.conf --------------------- redis配置文件
| | ├─ tls ---------------------------- redis的tls相关文件存放目录(考虑权限安全)
| | └─ ...
| |
| ├─ mysql --------------------------------------- mysql基目录
| | └─ ...
| |
| ├─ data ---------------------------------------- mysql数据目录
| | └─ ...
| |
| ├─ postgres ------------------------------------ pgsql基目录
| | ├─ tls ---------------------------- pgsql的tls相关文件存放目录(考虑权限安全)
| | └─ ...
| |
| ├─ pgData -------------------------------------- pgsql数据目录
| | ├─ postgresql.conf ---------------- pgsql服务器配置文件
| | ├─ pg_hba.conf -------------------- pgsql客户访问限制配置文件
| | └─ ...
| |
| ├─ php ----------------------------------------- PHP 目录
| | ├─ tools -------------------------- PHP通用工具存放目录
| | ├─ 84 ----------------------------- PHP8.4基目录
| | ├─ 74 ----------------------------- PHP7.4基目录
| | └─ ...
| |
| ├─ nginx --------------------------------------- nginx基目录
| | ├─ conf --------------------------- nginx配置目录
| | └─ ...
| |
| ├─ default ------------------------------------- 缺省站点路径
| | ├─ index.php ---------------------- 缺省站点php首页
| | └─ index.html --------------------- 缺省站点html页面
| |
| ├─ sites --------------------------------------- 虚拟主机配置文件目录
| |
| ├─ etc ----------------------------------------- 服务器相关日志文件目录
| | ├─ mysql -------------------------- mysql
| | | ├─ init.sql ---------- mysql初始化sql
| | | ├─ my.cnf ------------ mysql配置文件
| | | └─ ...
| | |
| | ├─ redis -------------------------- redis
| | | ├─ config ------------ 配置目录
| | | | ├─ custom ----- 自定义模块配置
| | | | └─ ...
| | | ├─ tls --------------- tls证书相关
| | | └─ ...
| | |
| | ├─ nginx -------------------------- nginx
| | | ├─ custom ------------ 自定义配置
| | | └─ ...
| | |
| | ├─ postgres ----------------------- postgres
| | | ├─ tls --------------- tls证书相关
| | | └─ ...
| | |
| |
| ├─ logs ---------------------------------------- 服务器相关日志文件目录
| | ├─ nginx -------------------------- nginx日志目录
| | | ├─ error.log --------- nginx错误日志
| | | ├─ access.log -------- nginx缺省访问日志
| | | └─ ...
| | |
| | ├─ redis ------------------------------------ redis日志目录
| | | ├─ redis.log ------------------- redis日志文件
| | | └─ ...
| | |
| | ├─ mysql ------------------------------------ nginx日志目录
| | | ├─ error.log ------------------- mysql错误日志
| | | ├─ binlog.index ---------------- mysql二进制日志
| | | └─ ...
| | |
| | ├─ postgres --------------------------------- pgsql日志目录
| | | ├─ wal_archive ----------------- pgsql预写式存放日志目录
| | | └─ ...
| | |
| | ├─ php -------------------------------------- php日志目录
| | | ├─ error-84.log ---------------- php-8.4错误日志
| | | ├─ error-74.log ---------------- php-7.4错误日志
| | | └─ ...
| | |
| | ├─ autoconf-2.69 ---------------------------- autoconf特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | └─ share -----------------------
| | |
| | ├─ openssl-1.1.1w --------------------------- openssl特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | ├─ openssl.cnf ----------------- openssl配置文件
| | | ├─ include --------------------- 头文件目录
| | | ├─ lib ------------------------- 库文件目录
| | | ├─ ├─ pkgconfig ---------- pkg-config 目录
| | | ├─ └─ ...
| | | └─ ...
| | |
| | ├─ icu4c-72.1 --------------------------- libicu特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | ├─ include --------------------- 头文件目录
| | | ├─ lib ------------------------- 库文件目录
| | | ├─ ├─ pkgconfig ---------- pkg-config 目录
| | | ├─ └─ ...
| | | └─ ...
| | |
| |
├─ ├─ ...
|
└─ /www ------------------------------------------------------ 站点基目录
===============================================================================
LNPP 环境目录
===============================================================================
├─ /server --------------------------------------------------- 服务目录
| ├─ sqlite -------------------------------------- SQLite3基目录
| | └─ ...
| |
| ├─ redis --------------------------------------- redis基目录
| | ├─ redis.conf --------------------- redis配置文件
| | ├─ tls ---------------------------- redis的tls相关文件存放目录(考虑权限安全)
| | └─ ...
| |
| ├─ postgres ------------------------------------ pgsql基目录
| | ├─ tls ---------------------------- pgsql的tls相关文件存放目录(考虑权限安全)
| | └─ ...
| |
| ├─ pgData -------------------------------------- pgsql数据目录
| | ├─ postgresql.conf ---------------- pgsql服务器配置文件
| | ├─ pg_hba.conf -------------------- pgsql客户访问限制配置文件
| | └─ ...
| |
| ├─ php ----------------------------------------- PHP 目录
| | ├─ tools -------------------------- PHP通用工具存放目录
| | ├─ 84 ----------------------------- PHP8.4基目录
| | ├─ 74 ----------------------------- PHP7.4基目录
| | └─ ...
| |
| ├─ nginx --------------------------------------- nginx基目录
| | ├─ conf --------------------------- nginx配置目录
| | └─ ...
| |
| ├─ default ------------------------------------- 缺省站点路径
| | ├─ index.php ---------------------- 缺省站点php首页
| | └─ index.html --------------------- 缺省站点html页面
| |
| ├─ etc ----------------------------------------- 服务器相关日志文件目录
| | ├─ redis -------------------------- redis
| | | ├─ config ------------ 配置目录
| | | | ├─ custom ----- 自定义模块配置
| | | | └─ ...
| | | ├─ tls --------------- tls证书相关
| | | └─ ...
| | |
| | ├─ nginx -------------------------- nginx
| | | ├─ custom ------------ 自定义配置
| | | └─ ...
| | |
| | ├─ postgres ----------------------- postgres
| | | ├─ tls --------------- tls证书相关
| | | └─ ...
| | |
| |
| ├─ sites --------------------------------------- 虚拟主机配置文件目录
| |
| ├─ logs ---------------------------------------- 服务器相关日志文件目录
| | ├─ nginx -------------------------- nginx日志目录
| | | ├─ error.log --------- nginx错误日志
| | | ├─ access.log -------- nginx缺省访问日志
| | | └─ ...
| | |
| | ├─ redis ------------------------------------ redis日志目录
| | | ├─ redis.log ------------------- redis日志文件
| | | └─ ...
| | |
| | ├─ postgres --------------------------------- pgsql日志目录
| | | ├─ wal_archive ----------------- pgsql预写式存放日志目录
| | | └─ ...
| | |
| | ├─ php -------------------------------------- php日志目录
| | | ├─ error-84.log ---------------- php-8.4错误日志
| | | ├─ error-74.log ---------------- php-7.4错误日志
| | | └─ ...
| | |
| | ├─ php -------------------------------------- php日志目录
| | | ├─ error-84.log ---------------- php-8.4错误日志
| | | ├─ error-74.log ---------------- php-7.4错误日志
| | | └─ ...
| | |
| | ├─ autoconf-2.69 ---------------------------- autoconf特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | └─ share -----------------------
| | |
| | ├─ openssl-1.1.1w --------------------------- openssl特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | ├─ openssl.cnf ----------------- openssl配置文件
| | | ├─ include --------------------- 头文件目录
| | | ├─ lib ------------------------- 库文件目录
| | | ├─ ├─ pkgconfig ---------- pkg-config 目录
| | | ├─ └─ ...
| | | └─ ...
| | |
| | ├─ icu4c-72.1 --------------------------- libicu特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | ├─ include --------------------- 头文件目录
| | | ├─ lib ------------------------- 库文件目录
| | | ├─ ├─ pkgconfig ---------- pkg-config 目录
| | | ├─ └─ ...
| | | └─ ...
| | |
| |
├─ ├─ ...
|
└─ /www ------------------------------------------------------ 站点基目录
===============================================================================
LNMP 环境目录
===============================================================================
├─ /server --------------------------------------------------- 服务目录
| ├─ sqlite -------------------------------------- SQLite3基目录
| | └─ ...
| |
| ├─ redis --------------------------------------- redis基目录
| | ├─ redis.conf --------------------- redis配置文件
| | ├─ tls ---------------------------- redis的tls相关文件存放目录(考虑权限安全)
| | └─ ...
| |
| ├─ mysql --------------------------------------- mysql基目录
| | └─ ...
| |
| ├─ data ---------------------------------------- mysql数据目录
| | └─ ...
| |
| ├─ php ----------------------------------------- PHP 目录
| | ├─ tools -------------------------- PHP通用工具存放目录
| | ├─ 84 ----------------------------- PHP8.4基目录
| | ├─ 74 ----------------------------- PHP7.4基目录
| | └─ ...
| |
| ├─ nginx --------------------------------------- nginx基目录
| | ├─ conf --------------------------- nginx配置目录
| | └─ ...
| |
| ├─ default ------------------------------------- 缺省站点路径
| | ├─ index.php ---------------------- 缺省站点php首页
| | └─ index.html --------------------- 缺省站点html页面
| |
| ├─ sites --------------------------------------- 虚拟主机配置文件目录
| |
| ├─ etc ----------------------------------------- 服务器相关日志文件目录
| | ├─ mysql -------------------------- mysql
| | | ├─ init.sql ---------- mysql初始化sql
| | | ├─ my.cnf ------------ mysql配置文件
| | | └─ ...
| | |
| | ├─ redis -------------------------- redis
| | | ├─ config ------------ 配置目录
| | | | ├─ custom ----- 自定义模块配置
| | | | └─ ...
| | | ├─ tls --------------- tls证书相关
| | | └─ ...
| | |
| | ├─ nginx -------------------------- nginx
| | | ├─ custom ------------ 自定义配置
| | | └─ ...
| |
| ├─ logs ---------------------------------------- 服务器相关日志文件目录
| | ├─ nginx -------------------------- nginx日志目录
| | | ├─ error.log --------- nginx错误日志
| | | ├─ access.log -------- nginx缺省访问日志
| | | └─ ...
| | |
| | ├─ redis ------------------------------------ redis日志目录
| | | ├─ redis.log ------------------- redis日志文件
| | | └─ ...
| | |
| | ├─ mysql ------------------------------------ nginx日志目录
| | | ├─ error.log ------------------- mysql错误日志
| | | ├─ binlog.index ---------------- mysql二进制日志
| | | └─ ...
| | |
| | ├─ php -------------------------------------- php日志目录
| | | ├─ error-84.log ---------------- php-8.4错误日志
| | | ├─ error-74.log ---------------- php-7.4错误日志
| | | └─ ...
| | |
| | ├─ autoconf-2.69 ---------------------------- autoconf特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | └─ share -----------------------
| | |
| | ├─ openssl-1.1.1w --------------------------- openssl特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | ├─ openssl.cnf ----------------- openssl配置文件
| | | ├─ include --------------------- 头文件目录
| | | ├─ lib ------------------------- 库文件目录
| | | ├─ ├─ pkgconfig ---------- pkg-config 目录
| | | ├─ └─ ...
| | | └─ ...
| | |
| | ├─ icu4c-72.1 --------------------------- libicu特定版本
| | | ├─ bin ------------------------- 执行文件存放目录
| | | ├─ include --------------------- 头文件目录
| | | ├─ lib ------------------------- 库文件目录
| | | ├─ ├─ pkgconfig ---------- pkg-config 目录
| | | ├─ └─ ...
| | | └─ ...
| | |
| |
├─ ├─ ...
|
└─ /www ------------------------------------------------------ 站点基目录
脚本文件
我们准备了几个 bash 脚本文件:
#!/usr/bin/env bash
# 创建 nginx 用户
groupadd -g 2001 nginx
useradd -c 'nginx service main process user' -g nginx -u 2001 -s /sbin/nologin -m nginx
cp -r /root/{.oh-my-zsh,.zshrc} /home/nginx
chown nginx:nginx -R /home/nginx/{.oh-my-zsh,.zshrc}
# 创建 postgres 用户
groupadd -g 2002 postgres
useradd -c 'postgres service main process user' -g postgres -u 2002 -s /sbin/nologin -m postgres
cp -r /root/{.oh-my-zsh,.zshrc} /home/postgres
chown postgres:postgres -R /home/postgres/{.oh-my-zsh,.zshrc}
# 创建 php-fpm 用户
groupadd -g 2003 php-fpm
useradd -c 'php-fpm service main process user' -g php-fpm -u 2003 -s /sbin/nologin -m php-fpm
cp -r /root/{.oh-my-zsh,.zshrc} /home/php-fpm
chown php-fpm:php-fpm -R /home/php-fpm/{.oh-my-zsh,.zshrc}
# php编译pgsql扩展,使用指定Postgres安装目录时,需要提供读取libpq相关权限
usermod -a -G postgres php-fpm
# 创建 redis 用户
groupadd -g 2005 redis
useradd -c 'redis service main process user' -g redis -u 2005 -s /sbin/nologin -m redis
cp -r /root/{.oh-my-zsh,.zshrc} /home/redis
chown redis:redis -R /home/redis/{.oh-my-zsh,.zshrc}
# 新版本开始使用tcp转发,并不需要考虑socket文件转发相关的权限问题
# php-fpm 主进程非特权用户时,需要考虑如下问题:
# nginx 如果是通过 sock 文件代理转发给 php-fpm,php-fpm 主进程创建 sock 文件时需要确保 nginx 子进程用户有读写 sock 文件的权限
# 方式1:采用 sock 文件权限 php-fpm:nginx 660 (nginx 权限较少,php-fpm 权限较多)
# usermod -G nginx php-fpm
# 方式2:采用 sock 文件权限 php-fpm:php-fpm 660 (nginx 权限较多,php-fpm 权限较少)
# usermod -G php-fpm nginx
# 创建 MySQL 用户
groupadd -g 2006 mysql
useradd -c 'mysql service main process user' -g mysql -u 2006 -s /sbin/nologin -m mysql
cp -r /root/{.oh-my-zsh,.zshrc} /home/mysql
chown mysql:mysql -R /home/mysql/{.oh-my-zsh,.zshrc}
# 创建 SQLite3 用户
groupadd -g 2007 sqlite
useradd -c 'sqlite main user' -g sqlite -u 2007 -s /sbin/nologin -m sqlite
cp -r /root/{.oh-my-zsh,.zshrc} /home/sqlite
chown sqlite:sqlite -R /home/sqlite/{.oh-my-zsh,.zshrc}
# 部署环境注释,开发环境取消注释,开发用户追加附属组,其中emad指开发用户
# - 部署环境不需要开发用户,可直接使用 nginx 用户作为 ftp、ssh 等上传工具的用户
usermod -a -G emad nginx
usermod -a -G emad php-fpm
usermod -a -G sqlite,redis,postgres,mysql,php-fpm,nginx emad
#!/usr/bin/env bash
# mkdir.bash
func_create(){
mkdir $1
}
server_array=(
"/www"
"/server"
"/server/default"
"/server/logs"
"/server/etc"
"/server/nginx"
"/server/logs/nginx"
"/server/etc/nginx"
"/server/etc/nginx/custom"
"/server/php"
"/server/php/84"
"/server/php/74"
"/server/php/tools"
"/server/logs/php"
"/server/postgres"
"/server/pgData"
"/server/logs/postgres"
"/server/logs/postgres/wal_archive"
"/server/etc/postgres"
"/server/etc/postgres/tls"
"/server/sites"
"/server/sites/ssl"
"/server/redis"
"/server/redis/rdbData"
"/server/logs/redis"
"/server/etc/redis"
"/server/etc/redis/tls"
"/server/etc/redis/config"
"/server/etc/redis/config/custom"
"/server/mysql"
"/server/data"
"/server/logs/mysql"
"/server/etc/mysql"
"/server/sqlite"
)
echo "-----开始创建server目录-----"
for((i=0;i<${#server_array[*]};i++));
do
echo ${server_array[i]}
func_create ${server_array[i]}
done
echo "-----server目录创建结束 -----"
#!/usr/bin/env bash
# 获取当前脚本的路径
SCRIPT_PATH="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
for i in `ls *.tar.gz`;
do
echo "gz解压" $i
tar -xzf $i
done
for i in `ls *.tar.bz2`;
do
echo "bz2解压" $i
tar -xjf $i
done
for i in `ls *.tar.xz`;
do
echo "xz解压" $i
tar -xJf $i
done
if [ -d "${SCRIPT_PATH}/php_ext" ]; then
EXT_DIR="${SCRIPT_PATH}/php_ext"
cd ${EXT_DIR}
for i in `ls *.tgz`;
do
echo "tgz解压" $i
tar -xzf $i
done
cd ${EXT_DIR}
rm package.xml
fi
#!/usr/bin/env bash
func_chown_nginx(){
chown nginx:nginx -R $1
find $1 -type f -exec chmod 640 {} \;
find $1 -type d -exec chmod 750 {} \;
}
func_chown_phpFpm(){
chown php-fpm:php-fpm -R $1
find $1 -type f -exec chmod 640 {} \;
find $1 -type d -exec chmod 750 {} \;
}
func_chown_postgres(){
chown postgres:postgres -R $1
find $1 -type f -exec chmod 640 {} \;
find $1 -type d -exec chmod 750 {} \;
}
func_chown_www(){
chown emad:emad -R $1
find $1 -type f -exec chmod 640 {} \;
find $1 -type d -exec chmod 750 {} \;
}
func_chown_redis(){
chown redis:redis -R $1
find $1 -type f -exec chmod 640 {} \;
find $1 -type d -exec chmod 750 {} \;
}
func_chown_mysql(){
chown mysql:mysql -R $1
find $1 -type f -exec chmod 640 {} \;
find $1 -type d -exec chmod 750 {} \;
}
func_chown_sqlite(){
chown sqlite:sqlite -R $1
find $1 -type f -exec chmod 640 {} \;
find $1 -type d -exec chmod 750 {} \;
}
chown_nginx_array=(
"/server/nginx"
"/server/logs/nginx"
"/server/etc/nginx"
"/server/sites"
);
chown_phpFpm_array=(
"/server/php"
"/server/logs/php"
);
chown_postgres_array=(
"/server/postgres"
"/server/pgData"
"/server/logs/postgres"
"/server/etc/postgres"
);
chown_www_array=(
"/www"
);
chown_redis_array=(
"/server/redis"
"/server/redis/rdbData"
"/server/logs/redis"
"/server/etc/redis"
);
chown_mysql_array=(
"/server/mysql"
"/server/data"
"/server/logs/mysql"
"/server/etc/mysql"
);
chown_sqlite_array=(
"/server/sqlite"
);
echo "-----开始设置nginx用户权限目录-----"
for((i=0;i<${#chown_nginx_array[*]};i++));
do
echo ${chown_nginx_array[i]}
func_chown_nginx ${chown_nginx_array[i]}
done
echo "-----nginx用户权限目录设置结束-----"
echo "-----开始设置 php-fpm 用户权限目录-----"
for((i=0;i<${#chown_phpFpm_array[*]};i++));
do
echo ${chown_phpFpm_array[i]}
func_chown_phpFpm ${chown_phpFpm_array[i]}
done
echo "-----php-fpm 用户权限目录设置结束-----"
echo "-----开始设置 postgres 用户权限目录-----"
for((i=0;i<${#chown_postgres_array[*]};i++));
do
echo ${chown_postgres_array[i]}
func_chown_postgres ${chown_postgres_array[i]}
done
echo "-----postgres 用户权限目录设置结束-----"
echo "-----开始设置 开发者 用户权限目录-----"
for((i=0;i<${#chown_www_array[*]};i++));
do
echo ${chown_www_array[i]}
func_chown_www ${chown_www_array[i]}
done
echo "-----开发者 用户权限目录设置结束-----"
echo "-----开始设置 redis 用户权限目录-----"
for((i=0;i<${#chown_redis_array[*]};i++));
do
echo ${chown_redis_array[i]}
func_chown_redis ${chown_redis_array[i]}
done
echo "-----redis 用户权限目录设置结束-----"
echo "-----开始设置 mysql 用户权限目录-----"
for((i=0;i<${#chown_mysql_array[*]};i++));
do
echo ${chown_mysql_array[i]}
func_chown_mysql ${chown_mysql_array[i]}
done
echo "-----mysql 用户权限目录设置结束-----"
echo "-----开始设置 sqlite 用户权限目录-----"
for((i=0;i<${#chown_sqlite_array[*]};i++));
do
echo ${chown_sqlite_array[i]}
func_chown_sqlite ${chown_sqlite_array[i]}
done
echo "-----sqlite 用户权限目录设置结束-----"
安装包列表
1. sqlite-autoconf-3500400.tar.gz
2. redis-8.2.1.tar.gz
3. mysql-8.4.6.tar.gz
4. postgresql-17.6.tar.bz2
5. php-7.4.33.tar.xz
- 动态扩展
- xdebug-3.1.6.tgz `最后支持版`
- apcu-5.1.27.tgz
- mongodb-1.20.1.tgz `最后支持版`
- redis-6.2.0.tgz
- yaml-2.2.5.tgz
- 依赖库
- openssl-1.1.1w.tar.gz
- icu4c-72_1-src.tgz
6. php-8.4.12.tar.xz
- 动态扩展
- xdebug-3.4.5.tgz
- apcu-5.1.27.tgz
- mongodb-2.1.1.tgz
- redis-6.2.0.tgz
- yaml-2.2.5.tgz
7. nginx-1.28.0.tar.gz
- openssl-3.5.2.tar.gz
- pcre2-10.45.tar.bz2
- zlib-1.3.1.tar.xz
1. sqlite-autoconf-3500400.tar.gz
2. redis-8.2.1.tar.gz
3. postgresql-17.6.tar.bz2
4. php-7.4.33.tar.xz
- 动态扩展
- xdebug-3.1.6.tgz `最后支持版`
- apcu-5.1.27.tgz
- mongodb-1.20.1.tgz `最后支持版`
- redis-6.2.0.tgz
- yaml-2.2.5.tgz
- 依赖库
- openssl-1.1.1w.tar.gz
- icu4c-72_1-src.tgz
5. php-8.4.12.tar.xz
- 动态扩展
- xdebug-3.4.2.tgz
- apcu-5.1.27.tgz
- mongodb-2.0.0.tgz
- redis-6.2.0.tgz
- yaml-2.2.5.tgz
6. nginx-1.28.0.tar.gz
- openssl-3.5.2.tar.gz
- pcre2-10.45.tar.bz2
- zlib-1.3.1.tar.xz
1. sqlite-autoconf-3500400.tar.gz
2. redis-8.2.1.tar.gz
3. mysql-8.4.6.tar.gz
4. php-7.4.33.tar.xz
- 动态扩展
- xdebug-3.1.6.tgz `最后支持版`
- apcu-5.1.27.tgz
- mongodb-1.20.1.tgz `最后支持版`
- redis-6.2.0.tgz
- yaml-2.2.5.tgz
- 依赖库
- openssl-1.1.1w.tar.gz
- icu4c-72_1-src.tgz
5. php-8.4.12.tar.xz
- 动态扩展
- xdebug-3.4.2.tgz
- apcu-5.1.27.tgz
- mongodb-2.0.0.tgz
- redis-6.2.0.tgz
- yaml-2.2.5.tgz
6. nginx-1.28.0.tar.gz
- openssl-3.5.2.tar.gz
- pcre2-10.45.tar.bz2
- zlib-1.3.1.tar.xz
源码包下载地址
package | url |
---|---|
SQLite3 | https://www.sqlite.org/ |
Redis | https://download.redis.io/redis-stable.tar.gz |
PostgreSQL | https://www.postgresql.org/ |
MySQL | https://www.mysql.com/ |
PHP | https://www.php.net/ |
PHP extend | http://pecl.php.net/ |
Nginx | http://nginx.org/ |
zlib | http://www.zlib.net/ |
openssl | https://openssl-library.org/ |
openssl-1.1.1w | https://www.openssl.org/source/openssl-1.1.1w.tar.gz |
pcre2 | https://github.com/PCRE2Project/pcre2 |
icu4c-72.1 | icu4c-72_1-src.tgz |
请求生命周期
Nginx 处理一次请求的生命周期
在 Nginx 中,处理一次请求的整个生命周期涉及到 master 进程和 worker 进程的协同工作。以下是详细介绍每个阶段中 master 进程和 worker 进程的作用:
初始化阶段:
- master 进程:负责读取和验证 Nginx 配置文件,初始化工作环境。
- worker 进程:由 master 进程根据配置文件中定义的 worker_processes 参数创建,数量通常与服务器的 CPU 核数一致,以充分利用多核特性。
监听和接受连接阶段:
- master 进程:在初始化完成后,master 进程会监听配置中指定的端口。
- worker 进程:负责接受来自客户端的连接请求。由于 worker 进程与 CPU 核心绑定,可以高效地处理并发连接。
处理请求阶段:
- master 进程:不直接参与请求的处理,主要负责监控和管理 worker 进程。
- worker 进程:每个 worker 进程只有一个线程,它们独立处理请求,执行如解析请求头、查找配置、重写 URI、访问权限检查等任务,并将结果返回给客户端。
发送响应阶段:
- master 进程:继续监控 worker 进程的状态,确保系统稳定运行。
- worker 进程:负责将响应数据发送回客户端,并记录访问日志。
关闭连接阶段:
- master 进程:不直接参与连接的关闭。
- worker 进程:在完成响应后,负责关闭与客户端的连接。
重新加载和退出阶段:
- master 进程:处理信号如 SIGTERM 来平滑退出或重新加载配置文件,创建新的 worker 进程来替换旧的 worker 进程,从而不影响正在处理的请求。
- worker 进程:在收到退出信号后,完成当前请求的处理,然后退出。
总结:
- 客户端发起的所有请求均由 worker 进程处理,而 master 进程不直接参与处理这些请求。
- 也就是说,客户端发起请求只使用了 worker 进程用户权限,不会涉及到 master 进程用户权限
问题:浏览器是否具备 Nginx worker 进程用户的权限?
浏览器作为客户端,不具备 nginx worker 进程用户的任何权限,浏览器只是通过建立的 TCP 连接来接收 Nginx worker 进程发送的内容
PHP-FPM 处理一次请求的生命周期
php-fpm 处理一次请求的生命周期包括请求接收、请求处理和请求结束三个阶段:
请求接收阶段:
当 php-fpm 的 master 进程接收到一个来自 Web 服务器(如 Nginx)的请求时,它会加锁以避免多个 worker 进程同时处理同一个请求,这在 Linux 中称为"惊群问题"。
Master 进程随后会指派一个可用的 worker 进程来处理这个请求。如果没有可用的 worker 进程,将返回错误,这也是在使用 Nginx 配合 php-fpm 时可能遇到 502 错误的一个原因。
请求处理阶段:
被指派的 worker 进程开始处理请求。这个过程中,worker 进程会执行 PHP 脚本并生成响应结果。如果处理过程超时,可能会返回 504 错误。
Worker 进程内部嵌入了 PHP 解释器,是 PHP 代码实际执行的地方。
请求结束阶段:
一旦 worker 进程完成了请求处理,它会将结果返回给 Web 服务器,从而完成整个请求的处理周期。
用户说明
在用户脚本中我们创建了多个用户:
用户名 | 说明 |
---|---|
emad | 开发者用户 |
sqlite | SQLite3 用户 |
redis | Redis 用户 |
postgres | PostgreSQL 用户 |
mysql | MySQL 用户 |
php-fpm | PHP-FPM 用户 |
nginx | Nginx 用户 |
Nginx
和 PHP-FPM
进程和用户关系比较复杂:
| process | user |
| ------------ | ----- |
| Nginx master | nginx |
| Nginx worker | nginx |
> Nginx 主进程:
- master 进程用户需要有 worker 进程用户的全部权限,master 进程用户类型:
1. 特权用户(root):worker 进程可以指定为其它非特权用户;
2. 非特权用户:worker 进程跟 master 进程是同一个用户。
> Nginx 工作进程:
- worker 进程负责处理实际的用户请求
- 代理转发和接收代理响应都是由 worker 进程处理
> Nginx 配置文件 `user` 指令限制说明:
- 主进程是特权用户(root):`user` 指令是有意义,用于指定工作进程用户和用户组
- 主进程是非特权用户:`user` 指令没有意义,会被 Nginx 程序忽略掉
| process | user |
| ----------------- | ------- |
| PHP-FPM master | php-fpm |
| PHP-FPM pool 进程 | php-fpm |
> PHP-FPM 主进程:
- master 进程负责管理 pool 进程
- master 进程创建和管理 pool 进程的 sock 文件
- master 进程需要有 pool 进程用户的全部权限,master 进程用户类型:
1. 特权用户(root):pool 进程可以指定为其它非特权用户
2. 非特权用户:pool 进程用户跟 master 进程用户相同
> PHP-FPM 工作池进程:
- pool 进程独立地处理请求,执行 PHP 脚本代码
- pool 进程处理完 PHP 代码后,会直接将结果返回给客户端
> 具体流程如下:
1. Nginx master 进程:当有新的请求到来时,master 进程会将其分配给一个 worker 进程来处理。
2. Nginx worker 进程:如果请求是静态资源,则直接返回给客户端;如果请求是 PHP 文件,则通过 `PHP-FPM pool` 进程的 sock 文件将请求转发给 PHP-FPM 进行处理。
3. PHP-FPM master 进程:当收到 `PHP-FPM pool` 进程的 sock 文件传递的请求时,master 进程会将其分配给一个 pool 进程来处理。
4. PHP-FPM pool 进程:pool 进程执行和处理 PHP 代码,并将返回结果发送给对应的 sock 文件
5. 返回结果:Nginx 的 worker 进程,接收 sock 文件的响应内容,再将处理后的动态内容返回给客户端。
> nginx 站点代理转发 php 请求时:
- Nginx 主进程用户不需要对 PHP-FPM 的 socket 文件拥有任何权限,处理请求的是工作进程
- Nginx 工作进程用户需要对 PHP-FPM 的 socket 文件具有 `读+写` 权限
1. 读取权限:Nginx 工作进程需要读取 socket 文件以发送请求到 PHP-FPM
2. 写入权限:Nginx 工作进程也需要写入权限,以便接收来自 PHP-FPM 的响应
- PHP-FPM 主进程用户需要对 sock 文件具有全部权限
1. 创建/删除 pool 进程的 sock 文件
2. 监听指定的端口或 Unix 套接字文件,以便接收来自 Web 服务器(如 Nginx)的请求。
3. 由
> PHP-FPM 的套接字文件:
- pool 进程的 sock 文件监听用户: `php-fpm`
- pool 进程的 sock 文件监听用户组: `nginx`
- pool 进程的 sock 文件监听权限: `0660`
- 用户 php-fpm 的附属用户组增加 `nginx`
用户职责
用户 nginx
是 Nginx worker 进程的 Unix 用户用户 php-fpm
是 PHP-FPM 子进程的 Unix 用户用户 emad
是开发者操作项目资源、文件的用户
用户权限
- 对静态文件需提供 `读` 的权限
- 对 php-fpm 的 `unix socket` 文件提供了读写的权限
浏览器等客户端使用 nginx 用户浏览网站:1)加载静态文件; 2) php-fpm 的 `unix socket` 文件传输
1. 使用 socket 转发,nginx 用户可作为 FPM 的监听用户,如:监听 socket、连接 web 服务器,权限设为 660
2. 使用 IP 转发,FPM 无需监听用户
1. FPM 进程运行的 Unix 用户,对 php 脚本、php 所需的配置文件需要 `读` 的权限;
2. 当 php 需要操作文件或目录时,需要提供 `读+写` 权限:
- 如:框架中记录运行时日志、缓存的 runtime 目录,就需要 `读+写` 全新
3. 除此以外,php-fpm 用户通常不需要其他权限
- 开发环境:需要对 php 文件、静态文件有 `读+写` 的权限;
- 部署环境:平时可以不提供任何权限,因为该用户与服务没有关联;
- 部署环境:对需要变动的文件,需要具有`读+写`的权限;
> 说明:emad 泛指开发者账户,你可以取其它名字
TIP
新版 lnpp 将采用 tcp 代理转发方式,所以 socket 文件权限不需要过多考虑
用户及用户组
下面这是开发环境的案例
1. 设置站点基目录权限
chown root:root /www
chmod 755 /www
chown emad:emad /www
chmod 750 -R /www
2. tp 站点权限案例
- 对于php文件,php-fpm 需要读取权限
- 对于页面文件,nginx 需要读取权限
- 对于上传文件,php-fpm 需要读写权限,nginx需要读取权限
- 对于缓存目录,php-fpm 需要读写权限
- 对于入口文件,php-fpm 需要读取权限, nginx不需要任何权限(直接走代理转发)
- 如果是开发环境,开发用户对所有文件都应该拥有读写权限
chown php-fpm:php-fpm -R /www/tp
find /www/tp -type f -exec chmod 440 {} \;
find /www/tp -type d -exec chmod 550 {} \;
# 部分目录需确保nginx可以访问和进入
chmod php-fpm:nginx -R /www/tp /www/tp/public /www/tp/public/static /www/tp/public/static/upload
# 部分文件需确保nginx可以访问
chmod 440 /www/tp/public/{favicon.ico,robots.txt}
# 缓存和上传目录需要写入权限
chmod 750 /www/tp/public/static/upload /www/tp/runtime
chown emad:emad -R /www/tp
find /www/tp -type f -exec chmod 640 {} \;
find /www/tp -type d -exec chmod 750 {} \;
chmod 770 /www/tp/public/static/upload
chmod 770 /www/tp/runtime
3. laravel 站点权限案例
- 对于php文件,php-fpm 需要读取权限
- 对于页面文件,nginx 需要读取权限
- 对于上传文件,php-fpm需要读写权限,nginx需要读取权限
- 对于缓存目录,php-fpm需要读写权限
- 对于入口文件,php-fpm需要读取权限, nginx不需要任何权限(直接走代理转发)
- 如果是开发环境,开发用户对所有文件都应该拥有读写权限
chown php-fpm:php-fpm -R /www/laravel
find /www/laravel -type f -exec chmod 440 {} \;
find /www/laravel -type d -exec chmod 550 {} \;
# 部分目录需确保nginx可以访问和进入
chmod php-fpm:nginx -R /www/laravel /www/laravel/public /www/laravel/public/static /www/laravel/public/static/upload
# 部分文件需确保nginx可以访问
chmod 440 /www/laravel/public/{favicon.ico,robots.txt}
# 缓存和上传目录需要写入权限
chmod 750 /www/laravel/public/static/upload
find /www/laravel/storage/ -type d -exec chmod 750 {} \;
chown emad:emad -R /www/laravel
find /www/laravel -type f -exec chmod 640 {} \;
find /www/laravel -type d -exec chmod 750 {} \;
# php读写 nginx读
chmod 770 /www/laravel/public/static/upload
# php读写
find /www/laravel/storage/* -type d -exec chmod 770 {} \;
umask 权限
# ~/.profile
# 第9行 umask 022处新建一行
umask 027 # 创建的文件权限是 640 目录权限是 750
# /etc/profile
# 第9行 umask 022 处新建一行
# 即使客户端上传了木马上来,也没得执行
umask 022 # 创建的文件权限是 644 目录权限是 755
# 提示:
# - php-fpm 用户的进程通常不会进入终端,所以只能在系统级别的初始化文件里设置
# - 但是这样一来其它用户的权限也会跟着改变,需要慎重处理
# - 建议使用php自身来限制上传文件的权限
注意
bash/zsh 配置文件开头需要增加一行:
# ~/.(bashrc|zshrc)
source ~/.profile
编译器选择
PostgreSQL 推荐使用 CLANG+LLVM
编译套件,--with-llvm
启用 JIT 支持,能提升查询性能;其余软件优先使用 GCC
编译套件。
内核调优
服务器中如果存在多个主要的服务,内核调优就需要兼顾到各种服务的特性,需要理解的是: 内核的配置仅代表这台服务器最大允许的值,软件包通常也会提供对应值。
这里通过修改 sysctl 配置文件(/etc/sysctl.d/*.conf
)来实现:
控制进程是否允许使用虚拟内存
- 0:进程只能使用物理内存(默认值)
- 1:进程可以使用比物理内存更多的虚拟内存
bashecho "vm.overcommit_memory = 1" > /etc/sysctl.d/overcommit_memory.conf
TCP 全连接队列(Accept 队列)最大长度,即已完成三次握手但未被应用层 accept()的连接数
- debian13 默认为 4096,通常足够
- 超过 65535 需确认内核是否支持
bashecho "net.core.somaxconn = 4096" > /etc/sysctl.d/somaxconn.conf
TCP 半连接队列(SYN 队列)最大长度,即处于 SYN_RECV 状态的未完成握手连接数
- debian13 默认为 512,存在高并发服务建议设为 4096
- 增大值会占用更多内存
bashecho "net.ipv4.tcp_max_syn_backlog = 4096" > /etc/sysctl.d/tcp_max_syn_backlog.conf
⚠️ 注意:
在 Debian 13 中,sysctl 的配置文件路径发生了显著变化,从传统的单一文件 /etc/sysctl.conf
转向了模块化的分散配置目录。
以下是 Debian13 具体的配置文件路径及其优先级规则:
路径 | 优先级 | 说明 |
---|---|---|
/etc/sysctl.d/*.conf | 1 | 优先级最高 |
/run/sysctl.d/*.conf | 2 | 重启失效 |
/usr/local/lib/sysctl.d/*.conf | 3 | 第三方软件配置 |
/usr/lib/sysctl.d/*.conf | 4 | 系统默认配置 |
/lib/sysctl.d/*.conf | 5 | 兼容旧版 |
sysctl --system # 加载所有配置文件
sysctl -a # 检查所有生效参数
sysctl vm.overcommit_memory # 查看特定参数
资源限制
/etc/security/limits.conf
用于设置用户或用户组在系统上的资源限制,目的是防止单个用户或进程过度消耗系统资源(如 CPU、内存、文件打开数等),从而保障系统的稳定性和安全性
配置文件 | 说明 |
---|---|
/etc/security/limits.conf | 资源限制主配置文件 |
/etc/security/limits.d/*.conf | 模块化管理配置文件 |
案例
echo "postgres soft nofile 65535
postgres hard nofile 65535" > /etc/security/limits.d/postgres.conf
echo "redis soft nofile 65535
redis hard nofile 65535" > /etc/security/limits.d/redis.conf
日志管理
Linux/Unix 系统使用 Logrotate
来管理日志文件。更多说明请参考 [Tutorial] 项目
echo "/server/logs/redis/redis-server.log {
monthly
maxsize 100M
missingok
rotate 12
compress
delaycompress
dateext
dateformat -%Y%m%d.%s
dateyesterday
create 0640 redis redis
sharedscripts
postrotate
if [ -f /run/redis/process.pid ]; then
/usr/bin/kill -USR1 \$(/bin/cat /run/redis/process.pid)
fi
endscript
}" > /etc/logrotate.d/redis
echo "/server/logs/nginx/*.log {
daily
maxsize 100M
missingok
rotate 30
compress
delaycompress
dateext
dateformat -%Y%m%d.%s
notifempty
create 0640 nginx nginx
sharedscripts
postrotate
if [ -f /run/nginx/process.pid ]; then
/usr/bin/kill -USR1 \$(/bin/cat /run/nginx/process.pid)
fi
endscript
}" > /etc/logrotate.d/nginx
echo "/server/logs/redis/redis-server.log {
# 轮转周期 daily/weekly/monthly/yearly 对应 每天/每周/每月/每年
# 每天轮转(切割)一次
daily
# 若日志大小超过100M,即使未到周期也轮转
maxsize 100M
# 日志文件不存在时忽略错误,继续执行
missingok
# 保留30个备份
rotate 30
# 压缩旧日志以节省空间(使用gzip)
compress
# 延迟压缩:本次轮转的日志在下一次轮转时才压缩
delaycompress
# 使用日期作为轮转文件的后缀
dateext
# 可选:自定义日期格式,例如 -20250901.1714900000
dateformat -%Y%m%d.%s
# 可选:使用前一天的日期而非轮转执行日期
dateyesterday
# 可选:使用前一天的日期而非轮转执行日期
# dateyesterday
# 复制当前日志文件后清空原文件,避免需重启Redis或发送信号(与 create 二选一)
# copytruncate
# 轮转后创建的新日志文件权限和属主(用户和组请根据实际情况调整)
create 0640 redis redis
# 所有日志文件处理完后,只执行一次postrotate脚本
sharedscripts
# 轮转后执行的脚本
postrotate
# 如果使用 copytruncate 无须发送信号,但有可能丢失极小量的日志
# 通过pid文件向Redis进程发送USR1信号,使其重新打开日志文件
if [ -f /run/redis/process.pid ]; then
# 这里是写入文件,需注意“$”符号转义
/usr/bin/kill -USR1 \$(/bin/cat /run/redis/process.pid)
fi
endscript
}" > /etc/logrotate.d/redis
常用指令 | 描述 |
---|---|
logrotate -vf /etc/logrotate.conf | 强制立即轮转所有配置文件(-v 显示详细过程) |
logrotate -vf /etc/logrotate.d/your_config | 强制立即轮转指定的配置文件(-v 显示详细过程) |
logrotate -d /etc/logrotate.d/your_config | 模拟轮转过程并显示详细信息 |
grep logrotate /var/log/syslog | 查看 logrotate 自身的执行记录和可能出现的错误信息 |
⚠️ copytruncate/create
两者区别
- copytruncate :
- 复制当前日志文件后清空原文件,避免需重启 Redis 或发送信号
- 对于不支持主动重新打开日志的程序非常有用
- 但理论上在复制和清空之间可能有极小量的日志丢失
- create :
- 确保日志不丢失,
- 需要配置
Logrotate
脚本,在轮转后对程序发送信号,重新打开日志
编译 OpenSSL 特定版本
如果对 openssl 依赖库有特殊版本需求,需要自行编译安装
# 作为公共依赖库,推荐以root用户安装它
mkdir /server/openssl-1.1.1w
cd /root/openssl-1.1.1w/
./config --prefix=/server/openssl-1.1.1w \
--openssldir=/server/openssl-1.1.1w \
no-shared \
zlib
# 作为公共依赖库,推荐以root用户安装它
mkdir /server/openssl-3.0.17
cd /root/openssl-3.0.17/
./config --prefix=/server/openssl-3.0.17 \
--openssldir=/server/openssl-3.0.17 \
no-shared \
zlib
make -j4 > make.log
make test > make-test.log
make install
# 设置新的 PKG_CONFIG_PATH,排除系统默认的 OpenSSL 库路径
export PKG_CONFIG_PATH=/server/openssl-1.1.1w/lib/pkgconfig:$PKG_CONFIG_PATH
# 使用下面指令检查,是否正确替换
pkg-config --path openssl,libssl,libcrypto
# 成功替换展示:
/server/openssl-1.1.1w/lib/pkgconfig/openssl.pc
/server/openssl-1.1.1w/lib/pkgconfig/libssl.pc
/server/openssl-1.1.1w/lib/pkgconfig/libcrypto.pc
# 未成功替换展示:
/usr/lib/x86_64-linux-gnu/pkgconfig/openssl.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/libssl.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/libcrypto.pc
# 设置新的 PKG_CONFIG_PATH,排除系统默认的 OpenSSL 库路径
export PKG_CONFIG_PATH=/server/openssl-3.0.17/lib64/pkgconfig:$PKG_CONFIG_PATH
# 使用下面指令检查,是否正确替换
pkg-config --path openssl,libssl,libcrypto
# 成功替换展示:
/server/openssl-3.0.17/lib/pkgconfig/openssl.pc
/server/openssl-3.0.17/lib/pkgconfig/libssl.pc
/server/openssl-3.0.17/lib/pkgconfig/libcrypto.pc
# 未成功替换展示:
/usr/lib/x86_64-linux-gnu/pkgconfig/openssl.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/libssl.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/libcrypto.pc
编译 ICU4C
特定版本
Debian/Ubuntu 系统仓库中对 ICU4C
库的命名约定为 libicu
。
系统自带的 libicu 版本如果不能满足编译环境需求,就需要通过手动编译特定版本来满足需求。
比如:debian13 自带的是 libicu-76.x,而 php7.4.33 需要 libicu-72.1 版本,此时我们就必须手动编译 libicu-72.1
。
下面以 Debin13 编译安装 ICU4C-72.1
为例:
mkdir /server/icu4c-72_1
wget https://github.com/unicode-org/icu/releases/download/release-72-1/icu4c-72_1-src.tgz
tar - xzf icu4c-72_1-src.tgz
cd icu/source/
./configure --prefix=/server/icu4c-72.1 \
--enable-static
make -j4 > make.log
make check > make-check.log
make install
# 设置新的 PKG_CONFIG_PATH,排除系统默认的 icu 库路径
export PKG_CONFIG_PATH=/server/icu4c-72.1/lib/pkgconfig:$PKG_CONFIG_PATH
# 使用下面指令检查,是否正确替换
pkg-config --path icu-i18n, icu-io, icu-uc
# 成功替换展示:
/server/icu4c-72.1/lib/pkgconfig/icu-i18n.pc
/server/icu4c-72.1/lib/pkgconfig/icu-io.pc
/server/icu4c-72.1/lib/pkgconfig/icu-uc.pc
# 未成功替换展示:
/usr/lib/x86_64-linux-gnu/pkgconfig/icu-i18n.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/icu-io.pc
/usr/lib/x86_64-linux-gnu/pkgconfig/icu-uc.pc
⚠️警告
debian13 编译安装 php7.4 遇到很多问题,存在大量问题需要解决,所以从 debian13 开始,不再兼容 php7.4
附录:
一、预构建包一键安装脚本
- Postgres 默认有个超级管理员用户 `admin` 密码 `1`
- MySQL 默认有个本地用户 `admin@localhost` 密码 `1`
- MySQL 默认有个局域网用户 `admin@'192.168.%.%'` 密码 `1`
- Redis 默认设置了全局密码 `1`
#!/usr/bin/env bash
printf "\033c"
echo_cyan(){
printf '\033[1;36m%b\033[0m\n' "$@"
}
echo_green(){
printf '\033[1;32m%b\033[0m\n' "$@"
}
echo_red(){
printf '\033[1;31m%b\033[0m\n' "$@"
}
echo_yellow(){
printf '\033[1;33m%b\033[0m\n' "$@"
}
#系统更新到最新
upgradeOS(){
echo_yellow "=================================================================="
echo_red "请使用纯净版操作系统,否则可能会造成系统破坏和数据丢失!!!"
echo_green "操作前请将系统更新至最新,指令如下:"
echo_yellow "=================================================================="
apt update
apt full-upgrade -y
echo_red "条件允许,建议重启系统"
}
#清空原先数据
cleanOldData(){
echo_yellow "=================================================================="
echo_green "清理旧数据"
echo_yellow "=================================================================="
echo_cyan "清理systemctl单元"
systemctl disable --now {redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service
rm /lib/systemd/system/{redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service
systemctl daemon-reload
echo_cyan "清理旧目录 /server,/www 如果有重要数据请先备份"
rm -rf /server /www
echo_cyan "删除旧用户 sqlite,redis,postgres,mysql,php-fpm,nginx 如果有重要数据请先备份"
userdel -r sqlite
userdel -r redis
userdel -r postgres
userdel -r mysql
userdel -r php-fpm
userdel -r nginx
groupdel sqlite
groupdel redis
groupdel postgres
groupdel mysql
groupdel php-fpm
groupdel nginx
}
#创建单个用户
createSingleUser(){
userName=$1
isSupportZsh=$2
echo_green "创建 $userName 用户"
groupadd $userName
useradd -c "$userName service main process user" -g $userName -s /sbin/nologin -m $userName
if [[ "$isSupportZsh" == '1' ]]; then
cp -r /root/{.oh-my-zsh,.zshrc} /home/$userName
chown $userName:$userName -R /home/$userName/{.oh-my-zsh,.zshrc}
fi
}
#创建用户
createUser(){
echo_yellow "=================================================================="
echo_green "创建sqlite,redis,postgres,mysql,php-fpm,nginx的进程用户"
echo_yellow "=================================================================="
echo_red "必须root用户安装并配置成功zsh,才允许支持zsh"
zshState=0
echo_cyan "是否支持启用zsh(1支持,默认不支持):"
read zshState
createSingleUser 'sqlite' $zshState
createSingleUser 'redis' $zshState
createSingleUser 'postgres' $zshState
createSingleUser 'mysql' $zshState
createSingleUser 'php-fpm' $zshState
createSingleUser 'nginx' $zshState
echo ' '
echo_yellow "=================================================================="
echo_green "处理php-fpm的socket文件授权问题"
echo_yellow "当 php-fpm 主进程非特权用户时,需要考虑socket文件权限问题:"
echo_yellow "nginx 如果是通过 sock 文件代理转发给 php-fpm,php-fpm 主进程创建\n sock 文件时需要确保 nginx 子进程用户有读写 sock 文件的权限"
echo_yellow " "
echo_yellow "方式1:采用 sock 文件权限 php-fpm:nginx 660 \n(nginx 权限较少,php-fpm 权限较多)"
echo_cyan "usermod -a -G nginx php-fpm"
echo_yellow " "
echo_yellow "方式2:采用 sock 文件权限 php-fpm:php-fpm 660 \n(nginx 权限较多,php-fpm 权限较少)"
echo_cyan "usermod -a -G php-fpm nginx"
echo_yellow " "
echo_green "此版本使用的是tcp转发,并不需要考虑socket文件转发相关的权限问题"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "php编译pgsql扩展,使用指定Postgres安装目录时,需要提供读取libpq相关权限:"
echo_green "php编译sqlite3扩展,使用指定sqlite3自带的pkgconfig时,需要提供读取对应目录的权限:"
echo_cyan "usermod -a -G postgres,sqlite php-fpm"
echo_green "如果使用 apt install libpq-dev libsqlite3-dev -y 依赖包则不需要"
echo_yellow " "
echo_green "此版本使用指定Postgres安装目录以及自己编译的SQLite3"
echo_yellow "=================================================================="
usermod -a -G postgres,sqlite php-fpm
}
#开发用户追加权限
devUserPower(){
devUserName=$1
echo_yellow "=================================================================="
echo_green "开发用户追加权限"
echo_yellow "web/php文件所属用户都是开发用户,所以nginx和php-fpm用户需要追加开发组"
echo_yellow " "
echo_red "部署环境请注释此函数,开发环境需要开启"
echo_red "部署环境不需要开发用户,可直接使用 nginx 用户作为 ftp、ssh 等上传工具的用户"
echo_yellow "=================================================================="
usermod -a -G $devUserName nginx
usermod -a -G $devUserName php-fpm
usermod -a -G sqlite,redis,postgres,mysql,php-fpm,nginx $devUserName
}
#安装依赖包
installPackage(){
echo_yellow "=================================================================="
echo_green "安装依赖"
echo_green "确保 SQLite3/Redis/PostgreSQL/MySQL/PHP/Nginx 必备依赖项"
echo_green "debian12 发行版,如因依赖导致部分功能异常,自行安装相应依赖包即可"
echo_red "注意1:该lnmpp包不兼容其他发行版,因为极有可能因为依赖问题,导致整个环境无法使用"
echo_red "注意2:部分依赖包在部署阶段可能没用,但由于没对单个功能测试,只能选择安装全部依赖"
echo_yellow "=================================================================="
apt install -y gcc g++ make clang pkg-config autoconf cmake zlib1g-dev gawk \
libedit-dev libreadline-dev tcl libssl-dev liblz4-dev libzstd-dev bison flex \
libpam0g-dev libxslt1-dev uuid-dev libsystemd-dev libxml2-dev xsltproc fop \
dbtoepub libldap-dev libsasl2-dev libncurses-dev libcurl4-openssl-dev \
libpng-dev libavif-dev libwebp-dev libjpeg-dev libxpm-dev libfreetype-dev \
libgmp-dev libonig-dev libcapstone-dev libsodium-dev libzip-dev libffi-dev \
libyaml-dev libgd-dev libgeoip-dev
}
#安装预构建包
InstallBuild(){
echo_yellow "=================================================================="
echo_green "解压lnmpp预构建包\n含两个目录"
echo_yellow " "
echo_cyan "/server"
echo_cyan "/www"
echo_yellow " "
echo_green "预先编译成功的lnmpp解压到服务器目录下"
echo_yellow "=================================================================="
tar -xJf ./lnmpp.tar.xz -C /
}
#重置Redis数字证书
resetRedisCertificate(){
redisTlsPath=/server/redis/tls
redisTlsScriptPath=/server/redis/gen-test-certs.sh
rm -rf $redisTlsPath
echo_yellow "=================================================================="
echo_green "创建一键生成redis数字证书脚本"
echo_yellow " "
echo_cyan "注意: 不能向其他用户开放权限"
echo_cyan "开发环境: 目录 750/ 文件 640"
echo_cyan "部署环境: 目录 700/ 文件 600"
echo_yellow " "
echo_yellow "=================================================================="
echo_cyan "[+] Create Redis certs script..."
echo "#\!/bin/bash
generate_cert() {
local name=\$1
local cn=\"\$2\"
local opts=\"\$3\"
local keyfile=$redisTlsPath/\${name}.key
local certfile=$redisTlsPath/\${name}.crt
[ -f \$keyfile ] || openssl genrsa -out \$keyfile 2048
openssl req \\
-new -sha256 \\
-subj \"/O=Redis Test/CN=\$cn\" \\
-key \$keyfile | \\
openssl x509 \\
-req -sha256 \\
-CA $redisTlsPath/ca.crt \\
-CAkey $redisTlsPath/ca.key \\
-CAserial $redisTlsPath/ca.txt \\
-CAcreateserial \\
-days 365 \\
\$opts \\
-out \$certfile
}
mkdir $redisTlsPath
[ -f $redisTlsPath/ca.key ] || openssl genrsa -out $redisTlsPath/ca.key 4096
openssl req \\
-x509 -new -nodes -sha256 \\
-key $redisTlsPath/ca.key \\
-days 3650 \\
-subj '/O=Redis Test/CN=Certificate Authority' \\
-out $redisTlsPath/ca.crt
cat > $redisTlsPath/openssl.cnf <<_END_
[ server_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = server
[ client_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = client
_END_
generate_cert server \"Server-only\" \"-extfile $redisTlsPath/openssl.cnf -extensions server_cert\"
generate_cert client \"Client-only\" \"-extfile $redisTlsPath/openssl.cnf -extensions client_cert\"
generate_cert redis \"Generic-cert\"
[ -f $redisTlsPath/redis.dh ] || openssl dhparam -out $redisTlsPath/redis.dh 2048
" > $redisTlsScriptPath
echo_cyan "[+] run Redis certs script..."
chmod +x $redisTlsScriptPath
$redisTlsScriptPath
echo_cyan "tls证书重置完成,是否删除一键生成Redis证书脚本(1删除/默认不删除):"
read isDeleteRedisTlsScript
if [[ "$isDeleteRedisTlsScript" == '1' ]]; then
rm $redisTlsScriptPath
fi
}
#重置PostgreSQL数字证书
resetPgsqlCertificate(){
pgsqlTlsPath=/server/postgres/tls
pgsqlTlsScriptPath=/server/postgres/gen-test-certs.sh
rm -rf $pgsqlTlsPath
echo_yellow "=================================================================="
echo_green "创建一键生成PostgreSQL数字证书脚本"
echo_yellow " "
echo_cyan "注意: 不能向其他用户开放权限"
echo_cyan "开发环境: 目录 750/ 文件 640"
echo_cyan "部署环境: 目录 700/ 文件 600"
echo_yellow " "
echo_yellow "=================================================================="
echo_cyan "[+] Create PostgreSQL certs script..."
echo "#\!/bin/bash
generate_cert() {
local name=\$1
local cn=\"\$2\"
local opts=\"\$3\"
local keyfile=$pgsqlTlsPath/\${name}.key
local certfile=$pgsqlTlsPath/\${name}.crt
[ -f \$keyfile ] || openssl genrsa -out \$keyfile 2048
openssl req \\
-new -sha256 \\
-subj \"/O=PostgreSQL Test/CN=\$cn\" \\
-key \$keyfile | \\
openssl x509 \\
-req -sha256 \\
-CA $pgsqlTlsPath/root.crt \\
-CAkey $pgsqlTlsPath/root.key \\
-CAserial $pgsqlTlsPath/root.txt \\
-CAcreateserial \\
-days 365 \\
\$opts \\
-out \$certfile
}
mkdir $pgsqlTlsPath
[ -f $pgsqlTlsPath/root.key ] || openssl genrsa -out $pgsqlTlsPath/root.key 4096
openssl req \\
-x509 -new -nodes -sha256 \\
-key $pgsqlTlsPath/root.key \\
-days 3650 \\
-subj '/O=PostgreSQL Test/CN=Certificate Authority' \\
-out $pgsqlTlsPath/root.crt
cat > $pgsqlTlsPath/openssl.cnf <<_END_
[ server_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = server
[ client_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = client
_END_
generate_cert server \"Server-only\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions server_cert\"
generate_cert client \"Client-only\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert\"
generate_cert client-admin \"admin\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert\"
generate_cert client-emad \"emad\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert\"
generate_cert pgsql \"Generic-cert\"
[ -f $pgsqlTlsPath/pgsql.dh ] || openssl dhparam -out $pgsqlTlsPath/pgsql.dh 2048
" > $pgsqlTlsScriptPath
echo_cyan "[+] run PostgreSQL certs script..."
chmod +x $pgsqlTlsScriptPath
$pgsqlTlsScriptPath
echo_cyan "tls证书重置完成,是否删除一键生成PostgreSQL证书脚本(1删除/默认不删除):"
read isDeletePgsqlTlsScript
if [[ "$isDeletePgsqlTlsScript" == '1' ]]; then
rm $pgsqlTlsScriptPath
fi
}
#修改文件权限
modFilePower(){
echo_yellow "=================================================================="
echo_green "文件权限"
echo_green "通常来讲压缩包里含的权限是正确的,这里重新执行一遍,更加稳妥"
echo_yellow "=================================================================="
echo_green "/server 目录权限"
chown root:root -R /server
chmod 755 /server
find /server/default -type f -exec chmod 644 {} \;
find /server/default -type d -exec chmod 755 {} \;
echo_green "/www 目录权限"
echo_red "开发环境使用emad用户(nginx/php-fpm 需加入 emad用户组)"
echo_red "部署环境通常是www用户(nginx/php-fpm 需加入 www用户组)"
chmod 750 /www
echo_green "nginx文件权限"
chown nginx:nginx -R /server/{nginx,sites}
find /server/{nginx,sites} -type f -exec chmod 640 {} \;
find /server/{nginx,sites} -type d -exec chmod 750 {} \;
chmod 750 -R /server/nginx/sbin
chown nginx:nginx -R /server/logs/nginx
chmod 750 /server/logs/nginx
echo_green "为nginx启用CAP_NET_BIND_SERVICE能力"
echo_red "注:每次修改nginx执行文件权限,都需要重新启用该能力"
setcap cap_net_bind_service=+eip /server/nginx/sbin/nginx
echo_green "postgres文件权限"
chown postgres:postgres -R /server/postgres /server/pgData /server/logs/postgres
find /server/postgres /server/logs/postgres -type f -exec chmod 640 {} \;
find /server/postgres /server/logs/postgres -type d -exec chmod 750 {} \;
find /server/postgres/tls -type f -exec chmod 600 {} \;
chmod 700 /server/pgData
chmod o-rwx -R /server/pgData
chmod g-w -R /server/pgData
chmod 750 -R /server/postgres/bin
echo_green "redis文件权限"
chown redis:redis -R /server/redis /server/logs/redis
find /server/redis /server/logs/redis -type f -exec chmod 640 {} \;
find /server/redis /server/logs/redis -type d -exec chmod 750 {} \;
chmod 750 -R /server/redis/bin
echo_green "sqlite3文件权限"
chown sqlite:sqlite -R /server/sqlite
find /server/sqlite -type f -exec chmod 640 {} \;
find /server/sqlite -type d -exec chmod 750 {} \;
chmod 750 -R /server/sqlite/bin
echo_green "MySQL文件权限"
chown mysql:mysql -R /server/mysql /server/data /server/logs/mysql /server/etc/mysql
find /server/mysql /server/logs/mysql /server/etc/mysql -type f -exec chmod 640 {} \;
find /server/mysql /server/logs/mysql /server/etc/mysql -type d -exec chmod 750 {} \;
chmod 700 /server/data
chmod 750 -R /server/mysql/bin
echo_green "php文件权限"
chown php-fpm:php-fpm -R /server/php /server/logs/php
find /server/php /server/logs/php /server/php/tools/ -type f -exec chmod 640 {} \;
find /server/php /server/logs/php /server/php/tools/ -type d -exec chmod 750 {} \;
chmod 750 -R /server/php/{74,84}/{bin,sbin}
chmod 640 /server/php/{84,74}/lib/php/extensions/no-debug-non-zts-*/*
chmod 750 /server/php/tools/{composer,php-cs-fixer}.phar
}
#安装systemctl单元
InstallSystemctlUnit(){
echo_yellow "=================================================================="
echo_green "加入systemctl守护进程\n含systemctl unit文件"
echo_yellow " "
echo_cyan "/lib/systemd/system/{redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow " "
echo_green "支持开启自动启动服务,非常规终止进程会自动启动服务"
echo_yellow "=================================================================="
echo_cyan "[+] Create nginx service..."
echo "[Unit]
Description=nginx-1.28.x
After=network.target
[Service]
Type=forking
User=nginx
Group=nginx
RuntimeDirectory=nginx
RuntimeDirectoryMode=0750
ExecStartPre=/server/nginx/sbin/nginx -t
ExecStart=/server/nginx/sbin/nginx -c /server/nginx/conf/nginx.conf
ExecReload=/server/nginx/sbin/nginx -s reload
ExecStop=/server/nginx/sbin/nginx -s quit
Restart=on-failure
PrivateTmp=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/nginx.service
echo_cyan "[+] Create php84-fpm service..."
echo "[Unit]
Description=The PHP 8.4 FastCGI Process Manager
After=network.target
[Service]
Type=notify
User=php-fpm
Group=php-fpm
RuntimeDirectory=php84-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/84/sbin/php-fpm --nodaemonize --fpm-config /server/php/84/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 \$MAINPID
PrivateTmp=true
ProtectSystem=full
PrivateDevices=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictNamespaces=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/php84-fpm.service
echo_cyan "[+] Create php74-fpm service..."
echo "[Unit]
Description=The PHP 7.4 FastCGI Process Manager
After=network.target
[Service]
Type=notify
User=php-fpm
Group=php-fpm
RuntimeDirectory=php74-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/74/sbin/php-fpm --nodaemonize --fpm-config /server/php/74/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
PrivateTmp=true
ProtectSystem=full
PrivateDevices=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictNamespaces=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/php74-fpm.service
echo_cyan "[+] Create postgres service..."
echo "[Unit]
Description=PostgreSQL database server
Documentation=man:postgres(1)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=postgres
Group=postgres
RuntimeDirectory=postgres
RuntimeDirectoryMode=0750
ExecStart=/server/postgres/bin/postgres -D /server/pgData
ExecReload=/bin/kill -HUP \$MAINPID
KillMode=mixed
KillSignal=SIGINT
TimeoutSec=infinity
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/postgres.service
echo_cyan "[+] Create MySQL service..."
echo "[Unit]
Description=MySQL Server 8.4.x
Documentation=man:mysqld(8)
After=network-online.target
Wants=network-online.target
After=syslog.target
[Service]
Type=notify
User=mysql
Group=mysql
RuntimeDirectory=mysql
RuntimeDirectoryMode=0750
ExecStart=/server/mysql/bin/mysqld --defaults-file=/server/etc/mysql/my.cnf
Restart=on-failure
PrivateTmp=false
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/mysqld-84.service
echo_cyan "[+] Create redis service..."
echo "[Unit]
Description=redis-7.4.x
After=network.target
[Service]
Type=forking
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0750
ExecStart=/server/redis/bin/redis-server /server/redis/redis.conf
ExecReload=/bin/kill -s HUP \$MAINPID
ExecStop=/bin/kill -s QUIT \$MAINPID
Restart=on-failure
PrivateTmp=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/redis.service
echo_green "Registered Service..."
systemctl daemon-reload
systemctl enable --now {redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service
}
echo_cyan "解压脚本同级目录下需存在源码压缩包 lnmpp.tar.xz"
echo_cyan "是否退出(1退出/默认继续):"
read isExit
if [[ "$isExit" == '1' ]]; then
exit 0
fi
#系统更新到最新
upgradeOS
echo_cyan "是否重启操作系统(1重启/默认不重启):"
read num
if [[ "$num" == '1' ]]; then
echo_cyan "停止向下执行,并重启系统"
sync;sync;sync;reboot
else
#清理旧数据
cleanOldData
echo ' '
#创建用户
createUser
echo ' '
#开发用户追加权限,部署环境请注释掉
echo_red "部署环境通常不需要授权"
echo_cyan "输入开发用户名,为其授权(为空不授权):"
read userName
if [[ -n "$userName" ]]; then
devUserPower $userName
fi
echo ' '
#安装依赖包
installPackage
echo ' '
#解压lnmpp预构建包到指定目录
InstallBuild
echo ' '
#是否重新生成tls证书
echo_cyan "是否重置数字证书(1重置/默认不重置):"
read isResetCertificate
if [[ "$isResetCertificate" == '1' ]]; then
resetRedisCertificate
resetPgsqlCertificate
fi
echo ' '
#修改文件权限
modFilePower
echo ' '
#安装systemctl单元
InstallSystemctlUnit
echo ' '
echo_red "注:下面这些是手动操作哦!!!"
echo_yellow "=================================================================="
echo_green "针对 Postgres用户 修改操作系统打开最大文件句柄数"
echo_yellow "为防止重复插入,请在 /etc/security/limits.conf 文件的结尾手动添加\n如下2行代码:"
echo_yellow " "
echo_cyan "postgres soft nofile 65535"
echo_cyan "postgres hard nofile 65535"
echo_yellow " "
echo_green "进行这一步操作的目的是防止linux操作系统内打开文件句柄数量的限制,\n避免不必要的故障"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "针对 redis 控制进程是否允许使用虚拟内存"
echo_yellow "为防止重复插入,请在 /etc/sysctl.conf 文件的结尾手动添加如下1行代码:"
echo_yellow " - 0:进程只能使用物理内存"
echo_yellow " - 1:进程可以使用比物理内存更多的虚拟内存"
echo_yellow " "
echo_cyan "vm.overcommit_memory = 1"
echo_yellow " "
echo_green "进行这一步操作的目的是防止redis在内存不足时,造成数据丢失"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "lnmpp安装完成!!!"
echo_yellow " - Postgres 默认有个超级管理员用户 admin 密码 1"
echo_yellow " - MySQL 默认有个本地用户 admin@localhost 密码 1"
echo_yellow " - MySQL 默认有个局域网用户 admin@'192.168.%.%' 密码 1"
echo_yellow " - Redis 默认设置了全局密码 1"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "systemctl 常用指令"
echo_yellow "重载 systemctl"
echo_yellow "systemctl daemon-reload"
echo_yellow "启用并开启服务"
echo_yellow "systemctl enable --now {redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "禁用并禁止服务"
echo_yellow "systemctl disable --now {redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "开启"
echo_yellow "systemctl start {redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "停止"
echo_yellow "systemctl stop {redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "查看状态"
echo_yellow "systemctl status {redis,mysqld-84,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "重新加载配置(部分服务器不支持重载配置文件)"
echo_yellow "systemctl reload nginx"
echo_yellow "=================================================================="
fi
#!/usr/bin/env bash
printf "\033c"
echo_cyan(){
printf '\033[1;36m%b\033[0m\n' "$@"
}
echo_green(){
printf '\033[1;32m%b\033[0m\n' "$@"
}
echo_red(){
printf '\033[1;31m%b\033[0m\n' "$@"
}
echo_yellow(){
printf '\033[1;33m%b\033[0m\n' "$@"
}
#系统更新到最新
upgradeOS(){
echo_yellow "=================================================================="
echo_red "请使用纯净版操作系统,否则可能会造成系统破坏和数据丢失!!!"
echo_green "操作前请将系统更新至最新,指令如下:"
echo_yellow "=================================================================="
apt update
apt full-upgrade -y
echo_red "条件允许,建议重启系统"
}
#清空原先数据
cleanOldData(){
echo_yellow "=================================================================="
echo_green "清理旧数据"
echo_yellow "=================================================================="
echo_cyan "清理systemctl单元"
systemctl disable --now {redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service
rm /lib/systemd/system/{redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service
systemctl daemon-reload
echo_cyan "清理旧目录 /server,/www 如果有重要数据请先备份"
rm -rf /server /www
echo_cyan "删除旧用户 sqlite,redis,mysql,php-fpm,nginx 如果有重要数据请先备份"
userdel -r sqlite
userdel -r redis
userdel -r mysql
userdel -r php-fpm
userdel -r nginx
groupdel sqlite
groupdel redis
groupdel mysql
groupdel php-fpm
groupdel nginx
}
#创建单个用户
createSingleUser(){
userName=$1
isSupportZsh=$2
echo_green "创建 $userName 用户"
groupadd $userName
useradd -c "$userName service main process user" -g $userName -s /sbin/nologin -m $userName
if [ "$isSupportZsh" = "1" ]; then
cp -r /root/{.oh-my-zsh,.zshrc} /home/$userName
chown $userName:$userName -R /home/$userName/{.oh-my-zsh,.zshrc}
fi
}
#创建用户
createUser(){
echo_yellow "=================================================================="
echo_green "创建 sqlite,redis,mysql,php-fpm,nginx 的进程用户"
echo_yellow "=================================================================="
echo_red "必须root用户安装并配置成功zsh,才允许支持zsh"
zshState=0
echo_cyan "是否支持启用zsh(1支持,默认不支持):"
read zshState
createSingleUser 'sqlite' $zshState
createSingleUser 'redis' $zshState
createSingleUser 'mysql' $zshState
createSingleUser 'php-fpm' $zshState
createSingleUser 'nginx' $zshState
echo ' '
echo_yellow "=================================================================="
echo_green "处理php-fpm的socket文件授权问题"
echo_yellow "当 php-fpm 主进程非特权用户时,需要考虑socket文件权限问题:"
echo_yellow "nginx 如果是通过 sock 文件代理转发给 php-fpm,php-fpm 主进程创建\n sock 文件时需要确保 nginx 子进程用户有读写 sock 文件的权限"
echo_yellow " "
echo_yellow "方式1:采用 sock 文件权限 php-fpm:nginx 660 \n(nginx 权限较少,php-fpm 权限较多)"
echo_cyan "usermod -a -G nginx php-fpm"
echo_yellow " "
echo_yellow "方式2:采用 sock 文件权限 php-fpm:php-fpm 660 \n(nginx 权限较多,php-fpm 权限较少)"
echo_cyan "usermod -a -G php-fpm nginx"
echo_yellow " "
echo_green "此版本使用的是tcp转发,并不需要考虑socket文件转发相关的权限问题"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "php编译sqlite3扩展,使用指定sqlite3自带的pkgconfig时,需要提供读取对应目录的权限:"
echo_cyan "usermod -a -G sqlite php-fpm"
echo_green "如果使用 apt install libsqlite3-dev -y 依赖包则不需要"
echo_yellow " "
echo_green "此版本使用自己编译的SQLite3"
echo_yellow "=================================================================="
usermod -a -G sqlite php-fpm
}
#开发用户追加权限
devUserPower(){
devUserName=$1
echo_yellow "=================================================================="
echo_green "开发用户追加权限"
echo_yellow "web/php文件所属用户都是开发用户,所以nginx和php-fpm用户需要追加开发组"
echo_yellow " "
echo_red "部署环境请注释此函数,开发环境需要开启"
echo_red "部署环境不需要开发用户,可直接使用 nginx 用户作为 ftp、ssh 等上传工具的用户"
echo_yellow "=================================================================="
usermod -a -G $devUserName nginx
usermod -a -G $devUserName php-fpm
usermod -G sqlite,redis,mysql,php-fpm,nginx $devUserName
}
#安装依赖包
installPackage(){
echo_yellow "=================================================================="
echo_green "安装依赖"
echo_green "确保 SQLite3/Redis/MySQL/PHP/Nginx 必备依赖项"
echo_green "debian12 发行版,如因依赖导致部分功能异常,自行安装相应依赖包即可"
echo_red "注意1:该lnmp包不兼容其他发行版,因为极有可能因为依赖问题,导致整个环境无法使用"
echo_red "注意2:部分依赖包在部署阶段可能没用,但由于没对单个功能测试,只能选择安装全部依赖"
echo_yellow "=================================================================="
apt install -y gcc g++ make cmake autoconf pkg-config tcl libxslt1-dev \
libxml2-dev libgd-dev libgeoip-dev libssl-dev libsystemd-dev \
libcurl4-openssl-dev libffi-dev libgmp-dev libonig-dev libsodium-dev libzip-dev \
libcapstone-dev libncurses-dev libldap-dev libsasl2-dev libbison-dev libpq-dev
}
#安装预构建包
InstallBuild(){
echo_yellow "=================================================================="
echo_green "解压lnmp预构建包\n含两个目录"
echo_yellow " "
echo_cyan "/server"
echo_cyan "/www"
echo_yellow " "
echo_green "预先编译成功的lnmp解压到服务器目录下"
echo_yellow "=================================================================="
tar -xJf ./lnmp.tar.xz -C /
}
#重置Redis数字证书
resetRedisCertificate(){
redisTlsPath=/server/redis/tls
redisTlsScriptPath=/server/redis/gen-test-certs.sh
rm -rf $redisTlsPath
echo_yellow "=================================================================="
echo_green "创建一键生成redis数字证书脚本"
echo_yellow " "
echo_cyan "注意: 不能向其他用户开放权限"
echo_cyan "开发环境: 目录 750/ 文件 640"
echo_cyan "部署环境: 目录 700/ 文件 600"
echo_yellow " "
echo_yellow "=================================================================="
echo_cyan "[+] Create Redis certs script..."
echo "#\!/bin/bash
generate_cert() {
local name=\$1
local cn=\"\$2\"
local opts=\"\$3\"
local keyfile=$redisTlsPath/\${name}.key
local certfile=$redisTlsPath/\${name}.crt
[ -f \$keyfile ] || openssl genrsa -out \$keyfile 2048
openssl req \\
-new -sha256 \\
-subj \"/O=Redis Test/CN=\$cn\" \\
-key \$keyfile | \\
openssl x509 \\
-req -sha256 \\
-CA $redisTlsPath/ca.crt \\
-CAkey $redisTlsPath/ca.key \\
-CAserial $redisTlsPath/ca.txt \\
-CAcreateserial \\
-days 365 \\
\$opts \\
-out \$certfile
}
mkdir $redisTlsPath
[ -f $redisTlsPath/ca.key ] || openssl genrsa -out $redisTlsPath/ca.key 4096
openssl req \\
-x509 -new -nodes -sha256 \\
-key $redisTlsPath/ca.key \\
-days 3650 \\
-subj '/O=Redis Test/CN=Certificate Authority' \\
-out $redisTlsPath/ca.crt
cat > $redisTlsPath/openssl.cnf <<_END_
[ server_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = server
[ client_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = client
_END_
generate_cert server \"Server-only\" \"-extfile $redisTlsPath/openssl.cnf -extensions server_cert\"
generate_cert client \"Client-only\" \"-extfile $redisTlsPath/openssl.cnf -extensions client_cert\"
generate_cert redis \"Generic-cert\"
[ -f $redisTlsPath/redis.dh ] || openssl dhparam -out $redisTlsPath/redis.dh 2048
" > $redisTlsScriptPath
echo_cyan "[+] run Redis certs script..."
chmod +x $redisTlsScriptPath
$redisTlsScriptPath
echo_cyan "tls证书重置完成,是否删除一键生成Redis证书脚本(1删除/默认不删除):"
read isDeleteRedisTlsScript
if [[ "$isDeleteRedisTlsScript" == '1' ]]; then
rm $redisTlsScriptPath
fi
}
#修改文件权限
modFilePower(){
echo_yellow "=================================================================="
echo_green "文件权限"
echo_green "通常来讲压缩包里含的权限是正确的,这里重新执行一遍,更加稳妥"
echo_yellow "=================================================================="
echo_green "/server 目录权限"
chown root:root -R /server
chmod 755 /server
find /server/default -type f -exec chmod 644 {} \;
find /server/default -type d -exec chmod 755 {} \;
echo_green "/www 目录权限"
echo_red "开发环境使用emad用户(nginx/php-fpm 需加入 emad用户组)"
echo_red "部署环境通常是www用户(nginx/php-fpm 需加入 www用户组)"
chmod 750 /www
echo_green "nginx文件权限"
chown nginx:nginx -R /server/{nginx,sites}
find /server/{nginx,sites} -type f -exec chmod 640 {} \;
find /server/{nginx,sites} -type d -exec chmod 750 {} \;
chmod 750 -R /server/nginx/sbin
chown nginx:nginx -R /server/logs/nginx
chmod 750 /server/logs/nginx
echo_green "为nginx启用CAP_NET_BIND_SERVICE能力"
echo_red "注:每次修改nginx执行文件权限,都需要重新启用该能力"
setcap cap_net_bind_service=+eip /server/nginx/sbin/nginx
echo_green "redis文件权限"
chown redis:redis -R /server/redis /server/logs/redis
find /server/redis /server/logs/redis -type f -exec chmod 640 {} \;
find /server/redis /server/logs/redis -type d -exec chmod 750 {} \;
chmod 750 -R /server/redis/bin
echo_green "sqlite3文件权限"
chown sqlite:sqlite -R /server/sqlite
find /server/sqlite -type f -exec chmod 640 {} \;
find /server/sqlite -type d -exec chmod 750 {} \;
chmod 750 -R /server/sqlite/bin
echo_green "MySQL文件权限"
chown mysql:mysql -R /server/mysql /server/data /server/logs/mysql /server/etc/mysql
find /server/mysql /server/logs/mysql /server/etc/mysql -type f -exec chmod 640 {} \;
find /server/mysql /server/logs/mysql /server/etc/mysql -type d -exec chmod 750 {} \;
chmod 700 /server/data
chmod 750 -R /server/mysql/bin
echo_green "php文件权限"
chown php-fpm:php-fpm -R /server/php /server/logs/php
find /server/php /server/logs/php /server/php/tools/ -type f -exec chmod 640 {} \;
find /server/php /server/logs/php /server/php/tools/ -type d -exec chmod 750 {} \;
chmod 750 -R /server/php/{74,84}/{bin,sbin}
chmod 640 /server/php/{84,74}/lib/php/extensions/no-debug-non-zts-*/*
chmod 750 /server/php/tools/{composer,php-cs-fixer}.phar
}
#安装systemctl单元
InstallSystemctlUnit(){
echo_yellow "=================================================================="
echo_green "加入systemctl守护进程\n含systemctl unit文件"
echo_yellow " "
echo_cyan "/lib/systemd/system/{redis,mysqld-84,php84-fpm,nginx}.service"
echo_yellow " "
echo_green "支持开启自动启动服务,非常规终止进程会自动启动服务"
echo_yellow "=================================================================="
echo_cyan "[+] Create nginx service..."
echo "[Unit]
Description=nginx-1.28.x
After=network.target
[Service]
Type=forking
User=nginx
Group=nginx
RuntimeDirectory=nginx
RuntimeDirectoryMode=0750
ExecStartPre=/server/nginx/sbin/nginx -t
ExecStart=/server/nginx/sbin/nginx -c /server/nginx/conf/nginx.conf
ExecReload=/server/nginx/sbin/nginx -s reload
ExecStop=/server/nginx/sbin/nginx -s quit
Restart=on-failure
PrivateTmp=true
[Install]
WantedBy=multi-user.target
" >/lib/systemd/system/nginx.service
echo_cyan "[+] Create php84-fpm service..."
echo "[Unit]
Description=The PHP 8.4 FastCGI Process Manager
After=network.target
[Service]
Type=notify
User=php-fpm
Group=php-fpm
RuntimeDirectory=php84-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/84/sbin/php-fpm --nodaemonize --fpm-config /server/php/84/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 \$MAINPID
PrivateTmp=true
ProtectSystem=full
PrivateDevices=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictNamespaces=true
[Install]
WantedBy=multi-user.target
" >/lib/systemd/system/php84-fpm.service
echo_cyan "[+] Create php74-fpm service..."
echo "[Unit]
Description=The PHP 7.4 FastCGI Process Manager
After=network.target
[Service]
Type=notify
User=php-fpm
Group=php-fpm
RuntimeDirectory=php74-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/74/sbin/php-fpm --nodaemonize --fpm-config /server/php/74/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
PrivateTmp=true
ProtectSystem=full
PrivateDevices=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictNamespaces=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/php74-fpm.service
echo_cyan "[+] Create MySQL service..."
echo "[Unit]
Description=MySQL Server 8.4.x
Documentation=man:mysqld(8)
After=network-online.target
Wants=network-online.target
After=syslog.target
[Service]
Type=notify
User=mysql
Group=mysql
RuntimeDirectory=mysql
RuntimeDirectoryMode=0750
ExecStart=/server/mysql/bin/mysqld --defaults-file=/server/etc/mysql/my.cnf
Restart=on-failure
PrivateTmp=false
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/mysqld-84.service
echo_cyan "[+] Create redis service..."
echo "[Unit]
Description=redis-7.4.x
After=network.target
[Service]
Type=forking
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0750
ExecStart=/server/redis/bin/redis-server /server/redis/redis.conf
ExecReload=/bin/kill -s HUP \$MAINPID
ExecStop=/bin/kill -s QUIT \$MAINPID
Restart=on-failure
PrivateTmp=true
[Install]
WantedBy=multi-user.target
" >/lib/systemd/system/redis.service
echo_green "Registered Service..."
systemctl daemon-reload
systemctl enable --now {redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service
}
echo_cyan "解压脚本同级目录下需存在源码压缩包 lnmp.tar.xz"
echo_cyan "是否退出(1退出/默认继续):"
read isExit
if [ "$isExit" = "1" ]; then
exit 0
fi
#系统更新到最新
upgradeOS
echo_cyan "是否重启操作系统(1重启/默认不重启):"
read num
if [ "$num" = "1" ]; then
echo_cyan "停止向下执行,并重启系统"
sync;sync;sync;reboot
else
#清理旧数据
cleanOldData
echo ' '
#创建用户
createUser
echo ' '
#开发用户追加权限,部署环境请注释掉
echo_red "部署环境通常不需要授权"
userName=''
echo_cyan "输入开发用户名,为其授权(为空不授权):"
read userName
if [ ! -z '$userName' ]; then
devUserPower $userName
fi
echo ' '
#安装依赖包
installPackage
echo ' '
#解压lnmp预构建包到指定目录
InstallBuild
echo ' '
#是否重新生成tls证书
echo_cyan "是否重置数字证书(1重置/默认不重置):"
read isResetCertificate
if [[ "$isResetCertificate" == "1" ]]; then
resetRedisCertificate
fi
echo ' '
#修改文件权限
modFilePower
echo ' '
#安装systemctl单元
InstallSystemctlUnit
echo ' '
echo_yellow "=================================================================="
echo_green "针对 redis 控制进程是否允许使用虚拟内存"
echo_yellow "为防止重复插入,请在 /etc/sysctl.conf 文件的结尾手动添加如下1行代码:"
echo_yellow " - 0:进程只能使用物理内存"
echo_yellow " - 1:进程可以使用比物理内存更多的虚拟内存"
echo_yellow " "
echo_cyan "vm.overcommit_memory = 1"
echo_yellow " "
echo_green "进行这一步操作的目的是防止redis在内存不足时,造成数据丢失"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "lnmp安装完成!!!"
echo_yellow " - MySQL 默认有个本地用户 admin@localhost 密码 1"
echo_yellow " - MySQL 默认有个局域网用户 admin@'192.168.%.%' 密码 1"
echo_yellow " - Redis 默认设置了全局密码 1"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "systemctl 常用指令"
echo_yellow "重载 systemctl"
echo_yellow "systemctl daemon-reload"
echo_yellow "启用并开启服务"
echo_yellow "systemctl enable --now {redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "禁用并禁止服务"
echo_yellow "systemctl disable --now {redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "开启"
echo_yellow "systemctl start {redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "停止"
echo_yellow "systemctl stop {redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "查看状态"
echo_yellow "systemctl status {redis,mysqld-84,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "重新加载配置(部分服务器不支持重载配置文件)"
echo_yellow "systemctl reload nginx"
echo_yellow "=================================================================="
fi
#!/usr/bin/env bash
printf "\033c"
echo_cyan(){
printf '\033[1;36m%b\033[0m\n' "$@"
}
echo_green(){
printf '\033[1;32m%b\033[0m\n' "$@"
}
echo_red(){
printf '\033[1;31m%b\033[0m\n' "$@"
}
echo_yellow(){
printf '\033[1;33m%b\033[0m\n' "$@"
}
#系统更新到最新
upgradeOS(){
echo_yellow "=================================================================="
echo_red "请使用纯净版操作系统,否则可能会造成系统破坏和数据丢失!!!"
echo_green "操作前请将系统更新至最新,指令如下:"
echo_yellow "=================================================================="
apt update
apt full-upgrade -y
echo_red "条件允许,建议重启系统"
}
#清空原先数据
cleanOldData(){
echo_yellow "=================================================================="
echo_green "清理旧数据"
echo_yellow "=================================================================="
echo_cyan "清理systemctl单元"
systemctl disable --now {redis,postgres,php74-fpm,php84-fpm,nginx}.service
rm /lib/systemd/system/{redis,postgres,php74-fpm,php84-fpm,nginx}.service
systemctl daemon-reload
echo_cyan "清理旧目录 /server,/www 如果有重要数据请先备份"
rm -rf /server /www
echo_cyan "删除旧用户 sqlite,redis,postgres,php-fpm,nginx 如果有重要数据请先备份"
userdel -r sqlite
userdel -r redis
userdel -r postgres
userdel -r php-fpm
userdel -r nginx
groupdel sqlite
groupdel redis
groupdel postgres
groupdel php-fpm
groupdel nginx
}
#创建单个用户
createSingleUser(){
userName=$1
isSupportZsh=$2
echo_green "创建 $userName 用户"
groupadd $userName
useradd -c "$userName service main process user" -g $userName -s /sbin/nologin -m $userName
if [ "$isSupportZsh" = "1" ]; then
cp -r /root/{.oh-my-zsh,.zshrc} /home/$userName
chown $userName:$userName -R /home/$userName/{.oh-my-zsh,.zshrc}
fi
}
#创建用户
createUser(){
echo_yellow "=================================================================="
echo_green "创建 sqlite,redis,postgres,php-fpm,nginx 的进程用户"
echo_yellow "=================================================================="
echo_red "必须root用户安装并配置成功zsh,才允许支持zsh"
zshState=0
echo_cyan "是否支持启用zsh(1支持,默认不支持):"
read zshState
createSingleUser 'sqlite' $zshState
createSingleUser 'redis' $zshState
createSingleUser 'postgres' $zshState
createSingleUser 'php-fpm' $zshState
createSingleUser 'nginx' $zshState
echo ' '
echo_yellow "=================================================================="
echo_green "处理php-fpm的socket文件授权问题"
echo_yellow "当 php-fpm 主进程非特权用户时,需要考虑socket文件权限问题:"
echo_yellow "nginx 如果是通过 sock 文件代理转发给 php-fpm,php-fpm 主进程创建\n sock 文件时需要确保 nginx 子进程用户有读写 sock 文件的权限"
echo_yellow " "
echo_yellow "方式1:采用 sock 文件权限 php-fpm:nginx 660 \n(nginx 权限较少,php-fpm 权限较多)"
echo_cyan "usermod -a -G nginx php-fpm"
echo_yellow " "
echo_yellow "方式2:采用 sock 文件权限 php-fpm:php-fpm 660 \n(nginx 权限较多,php-fpm 权限较少)"
echo_cyan "usermod -a -G php-fpm nginx"
echo_yellow " "
echo_green "此版本使用的是tcp转发,并不需要考虑socket文件转发相关的权限问题"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "php编译pgsql扩展,使用指定Postgres安装目录时,需要提供读取libpq相关权限:"
echo_green "php编译sqlite3扩展,使用指定sqlite3自带的pkgconfig时,需要提供读取对应目录的权限:"
echo_cyan "usermod -a -G postgres,sqlite php-fpm"
echo_green "如果使用 apt install libpq-dev libsqlite3-dev -y 依赖包则不需要"
echo_yellow " "
echo_green "此版本使用指定Postgres安装目录以及自己编译的SQLite3"
echo_yellow "=================================================================="
usermod -a -G postgres,sqlite php-fpm
}
#开发用户追加权限
devUserPower(){
devUserName=$1
echo_yellow "=================================================================="
echo_green "开发用户追加权限"
echo_yellow "web/php文件所属用户都是开发用户,所以nginx和php-fpm用户需要追加开发组"
echo_yellow " "
echo_red "部署环境请注释此函数,开发环境需要开启"
echo_red "部署环境不需要开发用户,可直接使用 nginx 用户作为 ftp、ssh 等上传工具的用户"
echo_yellow "=================================================================="
usermod -a -G $devUserName nginx
usermod -a -G $devUserName php-fpm
usermod -G sqlite,redis,postgres,php-fpm,nginx $devUserName
}
#安装依赖包
installPackage(){
echo_yellow "=================================================================="
echo_green "安装依赖"
echo_green "确保 SQLite3/Redis/PostgreSQL/PHP/Nginx 必备依赖项"
echo_green "debian12 发行版,如因依赖导致部分功能异常,自行安装相应依赖包即可"
echo_red "注意1:该lnpp包不兼容其他发行版,因为极有可能因为依赖问题,导致整个环境无法使用"
echo_red "注意2:部分依赖包在部署阶段可能没用,但由于没对单个功能测试,只能选择安装全部依赖"
echo_yellow "=================================================================="
apt install -y gcc g++ make pkg-config clang llvm-dev libsystemd-dev \
libcurl4-openssl-dev libxslt1-dev libxml2-dev libssl-dev libpam0g-dev \
zlib1g-dev libffi-dev libgmp-dev libonig-dev libsodium-dev libzip-dev \
libgd-dev libgeoip-dev liblz4-dev libzstd-dev libreadline-dev \
libcapstone-dev flex bison
}
#安装预构建包
InstallBuild(){
echo_yellow "=================================================================="
echo_green "解压lnpp预构建包\n含两个目录"
echo_yellow " "
echo_cyan "/server"
echo_cyan "/www"
echo_yellow " "
echo_green "预先编译成功的lnpp解压到服务器目录下"
echo_yellow "=================================================================="
tar -xJf ./lnpp.tar.xz -C /
}
#重置Redis数字证书
resetRedisCertificate(){
redisTlsPath=/server/redis/tls
redisTlsScriptPath=/server/redis/gen-test-certs.sh
rm -rf $redisTlsPath
echo_yellow "=================================================================="
echo_green "创建一键生成redis数字证书脚本"
echo_yellow " "
echo_cyan "注意: 不能向其他用户开放权限"
echo_cyan "开发环境: 目录 750/ 文件 640"
echo_cyan "部署环境: 目录 700/ 文件 600"
echo_yellow " "
echo_yellow "=================================================================="
echo_cyan "[+] Create Redis certs script..."
echo "#\!/bin/bash
generate_cert() {
local name=\$1
local cn=\"\$2\"
local opts=\"\$3\"
local keyfile=$redisTlsPath/\${name}.key
local certfile=$redisTlsPath/\${name}.crt
[ -f \$keyfile ] || openssl genrsa -out \$keyfile 2048
openssl req \\
-new -sha256 \\
-subj \"/O=Redis Test/CN=\$cn\" \\
-key \$keyfile | \\
openssl x509 \\
-req -sha256 \\
-CA $redisTlsPath/ca.crt \\
-CAkey $redisTlsPath/ca.key \\
-CAserial $redisTlsPath/ca.txt \\
-CAcreateserial \\
-days 365 \\
\$opts \\
-out \$certfile
}
mkdir $redisTlsPath
[ -f $redisTlsPath/ca.key ] || openssl genrsa -out $redisTlsPath/ca.key 4096
openssl req \\
-x509 -new -nodes -sha256 \\
-key $redisTlsPath/ca.key \\
-days 3650 \\
-subj '/O=Redis Test/CN=Certificate Authority' \\
-out $redisTlsPath/ca.crt
cat > $redisTlsPath/openssl.cnf <<_END_
[ server_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = server
[ client_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = client
_END_
generate_cert server \"Server-only\" \"-extfile $redisTlsPath/openssl.cnf -extensions server_cert\"
generate_cert client \"Client-only\" \"-extfile $redisTlsPath/openssl.cnf -extensions client_cert\"
generate_cert redis \"Generic-cert\"
[ -f $redisTlsPath/redis.dh ] || openssl dhparam -out $redisTlsPath/redis.dh 2048
" > $redisTlsScriptPath
echo_cyan "[+] run Redis certs script..."
chmod +x $redisTlsScriptPath
$redisTlsScriptPath
echo_cyan "tls证书重置完成,是否删除一键生成Redis证书脚本(1删除/默认不删除):"
read isDeleteRedisTlsScript
if [[ "$isDeleteRedisTlsScript" == '1' ]]; then
rm $redisTlsScriptPath
fi
}
#重置PostgreSQL数字证书
resetPgsqlCertificate(){
pgsqlTlsPath=/server/postgres/tls
pgsqlTlsScriptPath=/server/postgres/gen-test-certs.sh
rm -rf $pgsqlTlsPath
echo_yellow "=================================================================="
echo_green "创建一键生成PostgreSQL数字证书脚本"
echo_yellow " "
echo_cyan "注意: 不能向其他用户开放权限"
echo_cyan "开发环境: 目录 750/ 文件 640"
echo_cyan "部署环境: 目录 700/ 文件 600"
echo_yellow " "
echo_yellow "=================================================================="
echo_cyan "[+] Create PostgreSQL certs script..."
echo "#\!/bin/bash
generate_cert() {
local name=\$1
local cn=\"\$2\"
local opts=\"\$3\"
local keyfile=$pgsqlTlsPath/\${name}.key
local certfile=$pgsqlTlsPath/\${name}.crt
[ -f \$keyfile ] || openssl genrsa -out \$keyfile 2048
openssl req \\
-new -sha256 \\
-subj \"/O=PostgreSQL Test/CN=\$cn\" \\
-key \$keyfile | \\
openssl x509 \\
-req -sha256 \\
-CA $pgsqlTlsPath/root.crt \\
-CAkey $pgsqlTlsPath/root.key \\
-CAserial $pgsqlTlsPath/root.txt \\
-CAcreateserial \\
-days 365 \\
\$opts \\
-out \$certfile
}
mkdir $pgsqlTlsPath
[ -f $pgsqlTlsPath/root.key ] || openssl genrsa -out $pgsqlTlsPath/root.key 4096
openssl req \\
-x509 -new -nodes -sha256 \\
-key $pgsqlTlsPath/root.key \\
-days 3650 \\
-subj '/O=PostgreSQL Test/CN=Certificate Authority' \\
-out $pgsqlTlsPath/root.crt
cat > $pgsqlTlsPath/openssl.cnf <<_END_
[ server_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = server
[ client_cert ]
keyUsage = digitalSignature, keyEncipherment
nsCertType = client
_END_
generate_cert server \"Server-only\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions server_cert\"
generate_cert client \"Client-only\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert\"
generate_cert client-admin \"admin\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert\"
generate_cert client-emad \"emad\" \"-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert\"
generate_cert pgsql \"Generic-cert\"
[ -f $pgsqlTlsPath/pgsql.dh ] || openssl dhparam -out $pgsqlTlsPath/pgsql.dh 2048
" > $pgsqlTlsScriptPath
echo_cyan "[+] run PostgreSQL certs script..."
chmod +x $pgsqlTlsScriptPath
$pgsqlTlsScriptPath
echo_cyan "tls证书重置完成,是否删除一键生成PostgreSQL证书脚本(1删除/默认不删除):"
read isDeletePgsqlTlsScript
if [[ "$isDeletePgsqlTlsScript" == '1' ]]; then
rm $pgsqlTlsScriptPath
fi
}
#修改文件权限
modFilePower(){
echo_yellow "=================================================================="
echo_green "文件权限"
echo_green "通常来讲压缩包里含的权限是正确的,这里重新执行一遍,更加稳妥"
echo_yellow "=================================================================="
echo_green "/server 目录权限"
chown root:root -R /server
chmod 755 /server
find /server/default -type f -exec chmod 644 {} \;
find /server/default -type d -exec chmod 755 {} \;
echo_green "/www 目录权限"
echo_red "开发环境使用emad用户(nginx/php-fpm 需加入 emad用户组)"
echo_red "部署环境通常是www用户(nginx/php-fpm 需加入 www用户组)"
chmod 750 /www
echo_green "nginx文件权限"
chown nginx:nginx -R /server/{nginx,sites}
find /server/{nginx,sites} -type f -exec chmod 640 {} \;
find /server/{nginx,sites} -type d -exec chmod 750 {} \;
chmod 750 -R /server/nginx/sbin
chown nginx:nginx -R /server/logs/nginx
chmod 750 /server/logs/nginx
echo_green "为nginx启用CAP_NET_BIND_SERVICE能力"
echo_red "注:每次修改nginx执行文件权限,都需要重新启用该能力"
setcap cap_net_bind_service=+eip /server/nginx/sbin/nginx
echo_green "postgres文件权限"
chown postgres:postgres -R /server/postgres /server/pgData /server/logs/postgres
find /server/postgres /server/logs/postgres -type f -exec chmod 640 {} \;
find /server/postgres /server/logs/postgres -type d -exec chmod 750 {} \;
find /server/postgres/tls -type f -exec chmod 600 {} \;
chmod 700 /server/pgData
chmod o-rwx -R /server/pgData
chmod g-w -R /server/pgData
chmod 750 -R /server/postgres/bin
echo_green "redis文件权限"
chown redis:redis -R /server/redis /server/logs/redis
find /server/redis /server/logs/redis -type f -exec chmod 640 {} \;
find /server/redis /server/logs/redis -type d -exec chmod 750 {} \;
chmod 750 -R /server/redis/bin
echo_green "sqlite3文件权限"
chown sqlite:sqlite -R /server/sqlite
find /server/sqlite -type f -exec chmod 640 {} \;
find /server/sqlite -type d -exec chmod 750 {} \;
chmod 750 -R /server/sqlite/bin
echo_green "php文件权限"
chown php-fpm:php-fpm -R /server/php /server/logs/php
find /server/php /server/logs/php /server/php/tools/ -type f -exec chmod 640 {} \;
find /server/php /server/logs/php /server/php/tools/ -type d -exec chmod 750 {} \;
chmod 750 -R /server/php/{74,84}/{bin,sbin}
chmod 640 /server/php/{84,74}/lib/php/extensions/no-debug-non-zts-*/*
chmod 750 /server/php/tools/{composer,php-cs-fixer}.phar
}
#安装systemctl单元
InstallSystemctlUnit(){
echo_yellow "=================================================================="
echo_green "加入systemctl守护进程\n含systemctl unit文件"
echo_yellow " "
echo_cyan "/lib/systemd/system/{redis,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow " "
echo_green "支持开启自动启动服务,非常规终止进程会自动启动服务"
echo_yellow "=================================================================="
echo_cyan "[+] Create nginx service..."
echo "[Unit]
Description=nginx-1.28.x
After=network.target
[Service]
Type=forking
User=nginx
Group=nginx
RuntimeDirectory=nginx
RuntimeDirectoryMode=0750
ExecStartPre=/server/nginx/sbin/nginx -t
ExecStart=/server/nginx/sbin/nginx -c /server/nginx/conf/nginx.conf
ExecReload=/server/nginx/sbin/nginx -s reload
ExecStop=/server/nginx/sbin/nginx -s quit
Restart=on-failure
PrivateTmp=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/nginx.service
echo_cyan "[+] Create php84-fpm service..."
echo "[Unit]
Description=The PHP 8.4 FastCGI Process Manager
After=network.target
[Service]
Type=notify
User=php-fpm
Group=php-fpm
RuntimeDirectory=php84-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/84/sbin/php-fpm --nodaemonize --fpm-config /server/php/84/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 \$MAINPID
PrivateTmp=true
ProtectSystem=full
PrivateDevices=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictNamespaces=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/php84-fpm.service
echo_cyan "[+] Create php74-fpm service..."
echo "[Unit]
Description=The PHP 7.4 FastCGI Process Manager
After=network.target
[Service]
Type=notify
User=php-fpm
Group=php-fpm
RuntimeDirectory=php74-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/74/sbin/php-fpm --nodaemonize --fpm-config /server/php/74/etc/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
PrivateTmp=true
ProtectSystem=full
PrivateDevices=true
ProtectKernelModules=true
ProtectKernelTunables=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
RestrictNamespaces=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/php74-fpm.service
echo_cyan "[+] Create postgres service..."
echo "[Unit]
Description=PostgreSQL database server
Documentation=man:postgres(1)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
User=postgres
Group=postgres
RuntimeDirectory=postgres
RuntimeDirectoryMode=0750
ExecStart=/server/postgres/bin/postgres -D /server/pgData
ExecReload=/bin/kill -HUP \$MAINPID
KillMode=mixed
KillSignal=SIGINT
TimeoutSec=infinity
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/postgres.service
echo_cyan "[+] Create redis service..."
echo "[Unit]
Description=redis-7.4.x
After=network.target
[Service]
Type=forking
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0750
ExecStart=/server/redis/bin/redis-server /server/redis/redis.conf
ExecReload=/bin/kill -s HUP \$MAINPID
ExecStop=/bin/kill -s QUIT \$MAINPID
Restart=on-failure
PrivateTmp=true
[Install]
WantedBy=multi-user.target
" > /lib/systemd/system/redis.service
echo_green "Registered Service..."
systemctl daemon-reload
systemctl enable --now {redis,postgres,php74-fpm,php84-fpm,nginx}.service
}
echo_cyan "解压脚本同级目录下需存在源码压缩包 lnpp.tar.xz"
echo_cyan "是否退出(1退出/默认继续):"
read isExit
if [ "$isExit" = "1" ]; then
exit 0
fi
#系统更新到最新
upgradeOS
echo_cyan "是否重启操作系统(1重启/默认不重启):"
read num
if [ "$num" = "1" ]; then
echo_cyan "停止向下执行,并重启系统"
sync;sync;sync;reboot
else
#清理旧数据
cleanOldData
echo ' '
#创建用户
createUser
echo ' '
#开发用户追加权限,部署环境请注释掉
echo_red "部署环境通常不需要授权"
userName=''
echo_cyan "输入开发用户名,为其授权(为空不授权):"
read userName
if [ ! -z '$userName' ]; then
devUserPower $userName
fi
echo ' '
#安装依赖包
installPackage
echo ' '
#解压lnpp预构建包到指定目录
InstallBuild
echo ' '
#是否重新生成tls证书
echo_cyan "是否重置数字证书(1重置/默认不重置):"
read isResetCertificate
if [[ "$isResetCertificate" == "1" ]]; then
resetRedisCertificate
resetPgsqlCertificate
fi
echo ' '
#修改文件权限
modFilePower
echo ' '
#安装systemctl单元
InstallSystemctlUnit
echo ' '
echo_red "注:下面这些是手动操作哦!!!"
echo_yellow "=================================================================="
echo_green "针对 Postgres用户 修改操作系统打开最大文件句柄数"
echo_yellow "为防止重复插入,请在 /etc/security/limits.conf 文件的结尾手动添加\n如下2行代码:"
echo_yellow " "
echo_cyan "postgres soft nofile 65535"
echo_cyan "postgres hard nofile 65535"
echo_yellow " "
echo_green "进行这一步操作的目的是防止linux操作系统内打开文件句柄数量的限制,\n避免不必要的故障"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "针对 redis 控制进程是否允许使用虚拟内存"
echo_yellow "为防止重复插入,请在 /etc/sysctl.conf 文件的结尾手动添加如下1行代码:"
echo_yellow " - 0:进程只能使用物理内存"
echo_yellow " - 1:进程可以使用比物理内存更多的虚拟内存"
echo_yellow " "
echo_cyan "vm.overcommit_memory = 1"
echo_yellow " "
echo_green "进行这一步操作的目的是防止redis在内存不足时,造成数据丢失"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "lnpp安装完成!!!"
echo_yellow " - Postgres 默认有个超级管理员用户 admin 密码 1"
echo_yellow " - Redis 默认设置了全局密码 1"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "systemctl 常用指令"
echo_yellow "重载 systemctl"
echo_yellow "systemctl daemon-reload"
echo_yellow "启用并开启服务"
echo_yellow "systemctl enable --now {redis,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "禁用并禁止服务"
echo_yellow "systemctl disable --now {redis,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "开启"
echo_yellow "systemctl start {redis,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "停止"
echo_yellow "systemctl stop {redis,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "查看状态"
echo_yellow "systemctl status {redis,postgres,php74-fpm,php84-fpm,nginx}.service"
echo_yellow "重新加载配置(部分服务器不支持重载配置文件)"
echo_yellow "systemctl reload nginx"
echo_yellow "=================================================================="
fi
二、输出重定向说明
在 Linux 系统中,输出重定向是一个非常重要的功能,它允许你将命令的输出内容(包括标准输出和标准错误输出)重定向到文件、其他命令或丢弃,而不是默认显示在终端上。掌握输出重定向可以帮助你更好地控制命令的输出,记录日志,调试程序等。
基本概念
在 Linux 中,每个命令通常有以下三种输出流:
流类型 | 文件描述符 | 含义 | 默认输出位置 | 英文别名 |
---|---|---|---|---|
标准输出 | 1 | 正常输出结果 | 终端 | Standard Output,stdout |
标准错误输出 | 2 | 错误或警告信息 | 终端 | Standard Error,stderr |
标准输入 | 0 | 输入来源 | 键盘输入 | Standard Input,stdin |
输出重定向主要涉及 stdout
(1)和 stderr
(2),通过重定向符号可以将这些输出流重定向到文件或其他地方。
常用输出重定向符号
符号 | 含义 | 示例 |
---|---|---|
> | 将 stdout 重定向到文件(覆盖) | command > file |
>> | 将 stdout 重定向到文件(追加) | command >> file |
2> | 将 stderr 重定向到文件(覆盖) | command 2> file |
2>> | 将 stderr 重定向到文件(追加) | command 2>> file |
&> | 将 stdout 和 stderr 重定向到文件(覆盖) | command &> file |
&>> | 将 stdout 和 stderr 重定向到文件(追加) | command &>> file |
2>&1 | 将 stderr 重定向到 stdout(覆盖) | command 2>&1 file |
| | 管道符号,传递信息给另 1 个命令 | ls -l / | grep 'server' |
tee | 将数据同时写入到文件和终端 | command | tee file |
案例展示
# 终端输出错误和警告,文件记录正常信息
cmake \
-DWITH_DEBUG=ON \
-DCMAKE_INSTALL_PREFIX=/server/mysql \
-DWITH_SYSTEMD=ON \
-DFORCE_COLORED_OUTPUT=ON \
-DWITH_MYSQLX=OFF \
-DWITH_UNIT_TESTS=OFF \
-DINSTALL_MYSQLTESTDIR= \
.. > stdout.log
# 终端输出正常信息,文件记录错误和警告
cmake \
-DWITH_DEBUG=ON \
-DCMAKE_INSTALL_PREFIX=/server/mysql \
-DWITH_SYSTEMD=ON \
-DFORCE_COLORED_OUTPUT=ON \
-DWITH_MYSQLX=OFF \
-DWITH_UNIT_TESTS=OFF \
-DINSTALL_MYSQLTESTDIR= \
.. 2> stdout.log