准备工作
这是 《Linux 下纯手工搭建 PHP 环境》 2026 年重构版本!
这几年我们不断迭代,文档存在遗留代码也存在错误的说明,本次重构主要涉及:
- 文档内容紧凑,提升阅读体验;
- 修复已知错误;
- 优化目录结构;
- 优化一键脚本;
- 升级一键构建包;
包列表
主要涉及发行版和软件包如下。
zsh
➜ ~ uname -a
Linux debian13 6.12.63+deb13-amd64 #1 SMP PREEMPT_DYNAMIC Debian 6.12.63-1 (2025-12-30) x86_64 GNU/Linux
root ➜ ~ lsb_release -a
No LSB modules are available.
Distributor ID: Debian
Description: Debian GNU/Linux 13 (trixie)
Release: 13
Codename: trixiemd
1. sqlite-autoconf-3520000.tar.gz
2. redis-8.6.1.tar.gz
3. postgresql-18.3.tar.bz2
4. php-8.5.3.tar.xz
- apcu-5.1.28.tgz
- redis-6.3.0.tgz
- mongodb-2.2.1.tgz
- xdebug-3.5.0.tgz
5. nginx-1.28.2.tar.gz
- openssl-3.5.5.tar.gz
- pcre2-10.47.tar.bz2
- zlib-1.3.2.tar.xz
6. mysql-8.4.8.tar.gzmd
| package | url |
| ---------- | --------------------------------------------- |
| SQLite3 | https://www.sqlite.org/ |
| Redis.1 | https://github.com/redis/redis-hashes |
| Redis.2 | https://download.redis.io/redis-stable.tar.gz |
| PostgreSQL | https://www.postgresql.org/ |
| 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/ |
| pcre2 | https://github.com/PCRE2Project/pcre2 |
| MySQL | https://www.mysql.com/ |zsh
root ➜ ~ lt3 /server -l --no-time --no-filesize
Permissions User Name
drwxr-xr-x root /server/ [环境根路径]
.rwxrwxrwx root ├── cleanLog.zsh* [一键清理脚本]
drwx------ mysql ├── data/ [MySQL数据]
drwxr-xr-x root ├── default/ [缺省站点路径]
.rw-r--r-- root │ ├── index.html
.rw-r--r-- root │ └── index.php
drwxr-xr-x root ├── etc/ [配置根路径]
drwxr-x--- mysql │ ├── mysql/ [MySQL配置目录]
.rw-r----- mysql │ │ ├── init.sql
.rw-r----- mysql │ │ └── my.cnf
drwxr-x--- nginx │ ├── nginx/ [NginxL配置目录]
drwxr-x--- nginx │ │ ├── custom/
.rw-r----- nginx │ │ └── nginx.conf
drwxr-x--- php │ ├── php/ [PHP配置目录]
drwxr-x--- php │ │ ├── 85/
drwxr-x--- php │ │ └── tools/
drwxr-x--- postgres │ ├── postgres/ [PostgreSQL配置目录]
drwx------ postgres │ │ └── tls/
drwxr-x--- redis │ └── redis/ [Redis配置目录]
drwxr-x--- redis │ ├── config/
drwx------ redis │ └── tls/
drwxr-xr-x root ├── logs/ [日志根路径]
drwxr-x--- mysql │ ├── mysql/ [MySQL日志目录]
drwxr-x--- mysql │ │ └── binlog/
drwxr-x--- nginx │ ├── nginx/ [Nginx日志目录]
drwxr-x--- nginx │ │ ├── access/
drwxr-x--- nginx │ │ └── error/
drwxr-x--- php │ ├── php/ [PHP日志目录]
drwxr-x--- postgres │ ├── postgres/ [Postgres日志目录]
drwxr-x--- postgres │ │ └── wal_archive/
drwxr-x--- redis │ └── redis/ [Redis日志目录]
drwxr-x--- redis │ └── rdbData/
drwxr-x--- mysql ├── mysql/ [MySQL安装路径]
drwxr-x--- mysql │ ├── bin/
.rwxr-x--- mysql │ │ ├── mysql*
.rwxr-x--- mysql │ │ ├── mysql_config*
.rwxr-x--- mysql │ │ ├── mysqladmin*
.rwxr-x--- mysql │ │ ├── mysqld*
.rwxr-x--- mysql │ │ ├── mysqld_pre_systemd*
.rwxr-x--- mysql │ │ ├── mysqld_safe*
.rwxr-x--- mysql │ │ ├── mysqldump*
.rwxr-x--- mysql │ │ └── ...
drwxr-x--- mysql │ └── ...
drwxr-x--- nginx ├── nginx/ [Nginx安装路径]
drwxr-x--- nginx │ ├── conf/
.rw-r----- nginx │ │ ├── fastcgi.conf
.rw-r----- nginx │ │ ├── fastcgi.conf.default
.rw-r----- nginx │ │ ├── fastcgi_params
.rw-r----- nginx │ │ ├── fastcgi_params.default
.rw-r----- nginx │ │ ├── mime.types
.rw-r----- nginx │ │ ├── mime.types.default
.rw-r----- nginx │ │ ├── nginx.conf
.rw-r----- nginx │ │ ├── nginx.conf.default
.rw-r----- nginx │ │ └── ...
drwxr-x--- nginx │ ├── sbin/
.rwxr-x--- nginx │ │ ├── nginx*
.rw-r----- nginx │ │ └── nginx.old
drwxr-x--- nginx │ └── ...
drwxr-xr-x root ├── ohmyzsh/ [oh-my-zsh 源码]
drwx------ postgres ├── pgData/ [PostgreSQL数据]
.rw------- postgres │ ├── pg_hba.conf
.rw------- postgres │ ├── pg_hba.conf.bak
.rw------- postgres │ ├── pg_ident.conf
.rw------- postgres │ ├── pg_ident.conf.bak
drwx------ postgres │ ├── pg_wal/
drwx------ postgres │ │ ├── archive_status/
drwx------ postgres │ │ ├── summaries/
drwx------ postgres │ │ └── ...
.rw------- postgres │ ├── postgresql.auto.conf
.rw------- postgres │ ├── postgresql.conf
.rw------- postgres │ ├── postgresql.conf.bak
.rw------- postgres │ ├── postmaster.opts
.rw------- postgres │ └── ...
drwxr-x--- php ├── php/ [PHP安装路径]
drwxr-x--- php │ └── 85/
drwxr-x--- postgres ├── postgres/ [PostgreSQL安装路径]
drwxr-x--- postgres │ ├── bin/
.rwxr-x--- postgres │ │ ├── initdb*
.rwxr-x--- postgres │ │ ├── pg_config*
.rwxr-x--- postgres │ │ ├── pg_ctl*
.rwxr-x--- postgres │ │ ├── pg_dump*
.rwxr-x--- postgres │ │ ├── psql*
.rwxr-x--- postgres │ │ └── ...
drwxr-x--- postgres │ └── ...
drwxr-x--- redis ├── redis/ [Redis安装路径]
drwxr-x--- redis │ └── bin/
.rwxr-x--- redis │ ├── redis-benchmark*
lrwxrwxrwx redis │ ├── redis-check-aof -> redis-server*
lrwxrwxrwx redis │ ├── redis-check-rdb -> redis-server*
.rwxr-x--- redis │ ├── redis-cli*
lrwxrwxrwx redis │ ├── redis-sentinel -> redis-server*
.rwxr-x--- redis │ └── redis-server*
drwxr-x--- nginx ├── sites/ [Nginx站点配置路径]
drwxr-x--- nginx │ ├── available/
drwxr-x--- nginx │ ├── enabled/
drwxr-x--- nginx │ └── tls/
drwxr-x--- sqlite3 └── sqlite3/ [SQLite3安装路径]
drwxr-x--- sqlite3 ├── bin/
.rwxr-x--- sqlite3 │ └── sqlite3*
drwxr-x--- sqlite3 ├── include/
.rw-r----- sqlite3 │ ├── sqlite3.h
.rw-r----- sqlite3 │ └── sqlite3ext.h
drwxr-x--- sqlite3 ├── lib/
.rw-r----- sqlite3 │ ├── libsqlite3.a
lrwxrwxrwx sqlite3 │ ├── libsqlite3.so -> libsqlite3.so.3.52.0
lrwxrwxrwx sqlite3 │ ├── libsqlite3.so.0 -> libsqlite3.so.3.52.0
.rw-r----- sqlite3 │ ├── libsqlite3.so.3.51.2
.rw-r----- sqlite3 │ ├── libsqlite3.so.3.52.0
drwxr-x--- sqlite3 │ └── pkgconfig/
drwxr-x--- sqlite3 └── ...一键脚本
这几个脚本可以快速创建、授权目录,清理系统缓存。
zsh
#!/usr/bin/env bash
# 用户列表
users=(
"2001:sqlite3"
"2002:redis"
"2003:postgres"
"2005:php"
"2006:nginx"
"2007:mysql"
);
# 函数定义
funcCreateUser() {
local uid username
IFS=':' read -r uid username <<< "$1"
echo "正在创建用户: $username (UID: $uid)"
groupadd -g $uid $username
useradd -c "$username related process user" \
-g $username -u $uid -s /sbin/nologin -m $username
cp -r /root/.zshrc /home/$username
chown $username:$username -R /home/$username/.zshrc
ln -s /server/ohmyzsh /home/$username/.oh-my-zsh
}
# 主循环
for user in "${users[@]}"; do
funcCreateUser "$user"
done
# 用户与组的关系
usermod -a -G postgres,sqlite3 php
usermod -a -G sqlite3,redis,postgres,php,nginx,mysql emad
# 开发者创建的文件 [nginx 工作进程用户] 和 [php 工作进程用户] 需要能读取
usermod -a -G emad nginx
usermod -a -G emad phpzsh
#!/usr/bin/env bash
items=(
'/www'
'/server'
'/server/default'
'/server/logs'
'/server/etc'
'/server/sqlite3'
'/server/redis'
'/server/logs/redis'
'/server/logs/redis/rdbData'
'/server/etc/redis'
'/server/etc/redis/tls'
'/server/etc/redis/config'
'/server/etc/redis/config/custom'
'/server/postgres'
'/server/pgData'
'/server/logs/postgres'
'/server/logs/postgres/wal_archive'
'/server/etc/postgres'
'/server/etc/postgres/tls'
'/server/php'
'/server/php/85'
'/server/logs/php'
'/server/etc/php'
'/server/etc/php/tools'
'/server/etc/php/85'
'/server/etc/php/85/php-fpm.d'
'/server/nginx'
'/server/logs/nginx'
'/server/logs/nginx/access'
'/server/logs/nginx/error'
'/server/etc/nginx'
'/server/etc/nginx/custom'
'/server/mysql'
'/server/data'
'/server/logs/mysql'
'/server/logs/mysql/binlog'
'/server/etc/mysql'
'/server/sites'
'/server/sites/tls'
'/server/sites/available'
'/server/sites/enabled'
)
# 主循环
for item in "${items[@]}"; do
if [ ! -d "$item" ]; then
mkdir -p "$item"
fi
donezsh
#!/usr/bin/env bash
FuncRunPower(){
local DirPerm filePerm
# 判断权限
if [[ "$2" == "root" ]]; then
DirPerm=755
filePerm=644
else
DirPerm=750
filePerm=640
fi
chown "$2":"$2" -R "$1"
find "$1" -type d -exec chmod $DirPerm {} \;
find "$1" -type f -exec chmod $filePerm {} \;
echo "目录 $1 权限已设置为 目录:$DirPerm 文件:$filePerm"
}
rootItems=(
'/server'
);
wwwItems=(
'/www'
);
sqlite3Items=(
'/server/sqlite3'
);
redisItems=(
'/server/redis'
'/server/logs/redis'
'/server/etc/redis'
);
postgresItems=(
'/server/postgres'
'/server/pgData'
'/server/logs/postgres'
'/server/etc/postgres'
);
phpItems=(
'/server/php'
'/server/logs/php'
'/server/etc/php'
);
nginxItems=(
'/server/nginx'
'/server/logs/nginx'
'/server/etc/nginx'
'/server/sites'
);
mysqlItems=(
'/server/mysql'
'/server/data'
'/server/logs/mysql'
'/server/etc/mysql'
);
# 循环
for item in "${rootItems[@]}"; do
FuncRunPower "$item" 'root'
done
for item in "${wwwItems[@]}"; do
FuncRunPower "$item" 'emad'
done
for item in "${sqlite3Items[@]}"; do
FuncRunPower "$item" 'sqlite3'
done
for item in "${redisItems[@]}"; do
FuncRunPower "$item" 'redis'
done
for item in "${postgresItems[@]}"; do
FuncRunPower "$item" 'postgres'
done
for item in "${phpItems[@]}"; do
FuncRunPower "$item" 'php'
done
for item in "${nginxItems[@]}"; do
FuncRunPower "$item" 'nginx'
done
for item in "${mysqlItems[@]}"; do
FuncRunPower "$item" 'mysql'
donezsh
#!/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' "$@"
}
echo_cyan "删除/var/cache/apt/archives/下所有包文件"
apt clean
echo_cyan "仅删除过期的缓存文件"
apt autoclean
echo_cyan "删除不再被依赖的软件包"
apt autoremove --purge
echo_cyan "立即清空日志"
rm -rf /var/log/*
echo_cyan "是否清理zsh_history文件(1清理/默认不清理):"
read num
if [[ "$num" = "1" ]]; then
echo_yellow "开始清理终端历史文件文件"
rm /home/{sqlite3,redis,postgres,php,nginx,mysql,emad}/.{zsh,bash}_history
rm /home/{sqlite3,redis,postgres,php,nginx,mysql,emad}/.{z,viminfo}
rm /home/{sqlite3,redis,postgres,php,nginx,mysql,emad}/.zcompdump-*
rm /root/.{zsh,bash}_history
rm /root/.{z,viminfo}
rm /root/.zcompdump-*
echo_yellow "清理终端历史文件结束"
else
echo_yellow "不清理 .zsh_history 文件"
fi
echo_red "警告⚠️:请谨慎执行此脚本!!!"
echo_yellow "清理日志需停止服务"
echo_cyan "是否清理lnmpp日志(1清理/默认不清理):"
read num1
if [ "$num1" = "1" ]; then
echo_green "先停止服务"
systemctl stop {redis,postgres,php85-fpm,nginx,mysqld}.service
echo_green "开始清理redis日志"
find /server/logs/redis/ -maxdepth 1 -type f -exec rm {} \;
echo_green "开始清理postgres日志"
find /server/logs/postgres/ -maxdepth 1 -type f -exec rm {} \;
echo_green "开始清理php日志"
find /server/logs/php/ -type f -exec rm {} \;
echo_green "开始清理nginx默认日志目录"
find /server/nginx/logs/ -type f -exec rm {} \;
echo_green "开始清理nginx错误日志"
find /server/logs/nginx/error/ -type f -exec rm {} \;
echo_green "开始清理nginx访问日志"
find /server/logs/nginx/access/ -type f -exec rm {} \;
echo_green "开始清理mysql错误日志"
find /server/logs/mysql/ -type f -exec rm {} \;
echo_green "清理lnmpp日志完成"
else
echo_yellow "不清理lnmpp日志"
fi
echo_red "警告⚠️:请谨慎执行此脚本!!!"
echo_cyan "是否清理二进制日志(1清理/默认不清理):"
read num2
if [ "$num2" = "1" ]; then
echo_green "先停止服务"
systemctl stop {redis,postgres,php85-fpm,nginx,mysqld}.service
echo_green "开始清理PostgreSQL预写式日志(已归档)"
rm /server/logs/postgres/wal_archive/*
# echo_green "开始清理PostgreSQL预写式日志(当前不可删除)"
# find /server/pgData/pg_wal/ -maxdepth 1 -type f -exec rm {} \;
echo_green "开始清理MySQL二进制日志"
rm /server/logs/mysql/binlog/*
echo_green "清理lnpp日志完成"
else
echo_yellow "不清理数据库二进制日志"
fi
echo_cyan "是否清理Redis本地存储(1清理/默认不清理):"
read num3
if [[ "$num3" = "1" ]]; then
echo_yellow "开始清理Redis本地存储"
find /server/logs/redis/rdbData/ -type f -exec rm {} \;
# find /server/logs/redis/rdbData/ -maxdepth 1 -type f -exec rm {} \;
# find /server/logs/redis/rdbData/appendonlydir/ -maxdepth 1 -type f -exec rm {} \;
echo_yellow "清理Redis本地存储结束"
else
echo_yellow "不清理Redis本地存储"
fi
echo_cyan "是否启动服务(1启动/默认不启动):"
read num2
if [ "$num2" = "1" ]; then
systemctl start {redis,postgres,php85-fpm,nginx,mysqld}.service
echo_green "服务已重新启动"
else
echo_yellow "未重启服务,请手动启动"
fi编译套件
这些包是编译软件时最常用到的依赖项
bash
apt install --no-install-recommends \
build-essential autoconf pkg-config -ybash
apt install --no-install-recommends \
tcl -ybash
apt install --no-install-recommends \
libsystemd-dev libssl-dev -ybash
apt install --no-install-recommends \
llvm-dev clang libicu-dev liblz4-dev libzstd-dev liburing-dev \
bison flex libreadline-dev zlib1g-dev uuid-dev -ybash
apt install --no-install-recommends \
libcurl4-openssl-dev libpng-dev libjpeg-dev libfreetype-dev \
libonig-dev libsodium-dev libargon2-dev -ybash
apt install --no-install-recommends \
libxslt1-dev libgd-dev libgeoip-dev -ybash
apt install --no-install-recommends \
cmake libtirpc-dev -y一键搭建PHP环境
1. 实现原理
确保依赖环境和服务安装文件两者均一样,就能确保服务正常运行!
这与apt安装原理类似,只不过apt做的更安全也更加复杂。
2. 环境要求
发行版的版本号一致或者依赖项目完全满足,如:编译和测试环境为
Debian 13.3Debian 13.3任意服务器均可以正常使用Debian 13.x其他次要版的服务器也可以正常使用,因为依赖是兼容的(小版本依赖只做修复更新)redhat只要开发者有能力有时间,将所有依赖项兼容上,也可以正常使用
一键安装包文件没有损坏
3. 一键安装脚本
sh
#!/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,php85-fpm,nginx,mysqld-84}.service
rm /lib/systemd/system/{redis,postgres,php85-fpm,nginx,mysqld-84}.service
rm /etc/systemd/system/{redis,postgres,php85-fpm,nginx,mysqld-84}.service
systemctl daemon-reload
echo_cyan "清理旧目录 /server,/www 如果有重要数据请先备份"
rm -rf /server /www
echo_cyan "删除旧的 SQLite3,Redis,PostgreSQL,PHP,Nginx,MySQL 进程用户"
userdel -r sqlite3
userdel -r redis
userdel -r postgres
userdel -r php
userdel -r nginx
userdel -r mysql
groupdel sqlite3
groupdel redis
groupdel postgres
groupdel php
groupdel nginx
groupdel mysql
}
#创建单个用户
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/.zshrc /home/$userName
ln -s /server/ohmyzsh/ /home/$userName
chown $userName:$userName /home/$userName/.zshrc
fi
}
#创建用户
createUser(){
echo_yellow "=================================================================="
echo_green "创建 SQLite3,Redis,PostgreSQL,PHP,Nginx,MySQL 的进程用户"
echo_yellow "=================================================================="
echo_red "必须root用户安装并配置成功zsh,才允许支持zsh"
zshState=0
echo_cyan "是否支持启用zsh(1支持,默认不支持):"
read zshState
createSingleUser 'sqlite3' $zshState
createSingleUser 'redis' $zshState
createSingleUser 'postgres' $zshState
createSingleUser 'php' $zshState
createSingleUser 'nginx' $zshState
createSingleUser 'mysql' $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:nginx 660 \n(nginx 权限较少,php-fpm 权限较多)"
echo_cyan "usermod -a -G nginx php"
echo_yellow " "
echo_yellow "方式2:采用 sock 文件权限 php:php 660 \n(nginx 权限较多,php 权限较少)"
echo_cyan "usermod -a -G php nginx"
echo_yellow " "
echo_green "此版本使用的是tcp转发,并不需要考虑socket文件转发相关的权限问题"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "php编译pgsql扩展,使用指定PostgreSQL安装目录时,需要提供读取libpq相关权限:"
echo_green "php编译sqlite3扩展,使用指定sqlite3自带的pkgconfig时,需要提供读取对应目录的权限:"
echo_cyan "usermod -a -G sqlite3,postgres php"
echo_green "如果使用 apt install libpq-dev libsqlite3-dev -y 依赖包则不需要"
echo_yellow " "
echo_green "此版本PHP使用指定Postgres安装目录并在编译时禁用了sqlite3扩展"
echo_yellow "=================================================================="
usermod -a -G sqlite3,postgres php
}
#开发用户追加权限
devUserPower(){
devUserName=$1
echo_yellow "=================================================================="
echo_green "开发用户追加权限"
echo_yellow "WEB/PHP文件所属用户都是开发用户,所以nginx和php用户需要追加开发组"
echo_yellow " "
echo_red "部署环境请注释此函数,开发环境需要开启"
echo_red "部署环境不需要开发用户,可直接使用 nginx 用户作为 ftp、ssh 等上传工具的用户"
echo_yellow "=================================================================="
usermod -a -G $devUserName nginx
usermod -a -G $devUserName php
usermod -a -G sqlite3,redis,postgres,php,nginx,mysql $devUserName
}
#安装依赖包
installPackage(){
echo_yellow "=================================================================="
echo_green "安装依赖"
echo_green "确保 PostgreSQL/PHP/Nginx 必备依赖项"
echo_green "debian13 发行版,如因依赖导致部分功能异常,自行安装相应依赖包即可"
echo_red "注意1:该lnmpp包不兼容其他发行版,因为极有可能因为依赖问题,导致整个环境无法使用"
echo_red "注意2:部分依赖包在部署阶段可能没用,但由于没对单个功能测试,只能选择安装全部依赖"
echo_yellow "=================================================================="
apt install --no-install-recommends \
build-essential autoconf pkg-config \
tcl \
libsystemd-dev libssl-dev \
llvm-dev clang libicu-dev liblz4-dev libzstd-dev liburing-dev \
bison flex libreadline-dev zlib1g-dev uuid-dev \
libcurl4-openssl-dev libpng-dev libjpeg-dev libfreetype-dev \
libonig-dev libsodium-dev libargon2-dev \
libxslt1-dev libgd-dev libgeoip-dev \
cmake libtirpc-dev \
-y
}
#安装预构建包
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(){
redisTlsScriptPath=/server/etc/redis/gen-test-certs.sh
rm -rf /server/etc/redis/tls
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..."
cat > $redisTlsScriptPath << 'EOF'
#!/bin/bash
# Generate some test certificates which are used by the regression test suite:
#
# tests/tls/ca.{crt,key} Self signed CA certificate.
# tests/tls/redis.{crt,key} A certificate with no key usage/policy restrictions.
# tests/tls/client.{crt,key} A certificate restricted for SSL client usage.
# tests/tls/server.{crt,key} A certificate restricted for SSL server usage.
# tests/tls/redis.dh DH Params file.
redisTlsPath=/server/etc/redis/tls
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
}
[ -d $redisTlsPath ] || 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
EOF
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(){
pgsqlTlsScriptPath=/server/etc/postgres/gen-test-certs.sh
rm -rf /server/etc/postgres/tls
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..."
cat > $pgsqlTlsScriptPath << 'EOF'
#!/bin/bash
# 这些文件是用于生成测试证书的,部署环境应从正规的数字证书的签发机构获取相关证书
#
# tls/root.{crt,key} CA证书用于签署其他证书,以建立信任链
# tls/pgsql.{crt,key} 这个证书可用于SSL/TLS连接中的任何用途
# tls/server.{crt,key} 只能用于SSL/TLS连接中的服务器身份验证
# tls/client.{crt,key} 只能用于SSL/TLS连接中的客户端身份验证
# tls/client-emad.{crt,key} 允许用户emad使用verify-full验证类型
# tls/client-admin.{crt,key} 允许用户admin使用verify-full验证类型
# tls/pgsql.dh 在SSL/TLS握手过程中协商临时密钥,以确保通信的安全性
pgsqlTlsPath=/server/etc/postgres/tls
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
}
[ -d $pgsqlTlsPath ] || 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-replication "repl_user" "-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert"
generate_cert pgsql "Generic-cert"
[ -f $pgsqlTlsPath/pgsql.dh ] || openssl dhparam -out $pgsqlTlsPath/pgsql.dh 2048
EOF
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 需加入 emad用户组)"
echo_red "部署环境通常是www用户(nginx/php 需加入 www用户组)"
chmod 750 /www
echo_green "ohmyzsh文件权限"
chown root:root -R /server/ohmyzsh
find /server/ohmyzsh -type f -exec chmod 644 {} \;
find /server/ohmyzsh -type d -exec chmod 755 {} \;
echo_green "SQLite3文件权限"
chown sqlite3:sqlite3 -R /server/sqlite3
find /server/sqlite3 -type f -exec chmod 640 {} \;
find /server/sqlite3 -type d -exec chmod 750 {} \;
chmod 750 -R /server/sqlite3/bin
echo_green "Redis文件权限"
chown redis:redis -R /server/redis /server/logs/redis /server/etc/redis
find /server/redis /server/logs/redis /server/etc/redis -type f -exec chmod 640 {} \;
find /server/redis /server/logs/redis /server/etc/redis -type d -exec chmod 750 {} \;
chmod 750 -R /server/redis/bin
find /server/etc/redis/tls -type f -exec chmod 600 {} \;
find /server/etc/redis/tls -type d -exec chmod 700 {} \;
echo_green "PostgreSQL文件权限"
chown postgres:postgres -R /server/postgres /server/pgData /server/logs/postgres /server/etc/postgres
find /server/postgres /server/logs/postgres /server/etc/postgres -type f -exec chmod 640 {} \;
find /server/postgres /server/logs/postgres /server/etc/postgres -type d -exec chmod 750 {} \;
chmod 750 -R /server/postgres/bin
find /server/etc/postgres/tls /server/pgData -type f -exec chmod 600 {} \;
find /server/etc/postgres/tls /server/pgData -type d -exec chmod 700 {} \;
echo_green "PHP文件权限"
chown php:php -R /server/php /server/logs/php /server/etc/php
find /server/php /server/logs/php /server/etc/php -type f -exec chmod 640 {} \;
find /server/php /server/logs/php /server/etc/php -type d -exec chmod 750 {} \;
chmod 750 /server/etc/php/tools/{composer,php-cs-fixer-v3}.phar
chmod 750 -R /server/php/85/{bin,sbin}
chmod 640 /server/php/85/lib/php/extensions/no-debug-non-zts-*/*
echo_green "Nginx文件权限"
chown nginx:nginx -R /server/{nginx,sites}
chown nginx:nginx -R /server/{etc,logs}/nginx
find /server/{nginx,sites} -type f -exec chmod 640 {} \;
find /server/{nginx,sites} -type d -exec chmod 750 {} \;
find /server/{etc,logs}/nginx -type f -exec chmod 640 {} \;
find /server/{etc,logs}/nginx -type d -exec chmod 750 {} \;
find /server/sites/tls -type f -exec chmod 600 {} \;
chmod 750 /server/nginx/sbin/nginx
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
}
#安装systemctl单元
InstallSystemctlUnit(){
echo_yellow "=================================================================="
echo_green "加入systemctl守护进程\n含systemctl unit文件"
echo_yellow " "
echo_cyan "/lib/systemd/system/{redis,postgres,php85-fpm,nginx,mysqld-84}.service"
echo_yellow " "
echo_green "支持开启自动启动服务,非常规终止进程会自动启动服务"
echo_yellow "=================================================================="
echo_cyan "[+] Create Redis service..."
cat > /etc/systemd/system/redis.service << 'EOF'
[Unit]
Description=Redis In-Memory Data Store
After=network.target
[Service]
Type=notify
UMask=0027
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0750
ExecStart=/server/redis/bin/redis-server /server/etc/redis/config/redis.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/server/redis/bin/redis-cli shutdown
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=60s
Restart=on-failure
RestartSec=10s
LimitNOFILE=10000
LimitNPROC=10000
LimitMEMLOCK=infinity
LimitAS=infinity
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/redis /run/redis /server/logs/redis
[Install]
WantedBy=multi-user.target
EOF
echo_cyan "[+] Create PostgreSQL service..."
cat > /etc/systemd/system/postgres.service << 'EOF'
[Unit]
Description=PostgreSQL database server
Documentation=man:postgres(1)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
UMask=0027
User=postgres
Group=postgres
RuntimeDirectory=postgres
RuntimeDirectoryMode=0750
ExecStart=/server/postgres/bin/postgres -D /server/pgData
ExecReload=/bin/kill -HUP $MAINPID
ExecReload=/server/postgres/bin/pg_ctl reload
ExecStop=/server/postgres/bin/pg_ctl -D /server/pgData stop -m smart
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=120s
TimeoutStartSec=infinity
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536
LimitNPROC=65536
LimitMEMLOCK=infinity
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/postgres /run/postgres /server/pgData /server/logs/postgres
[Install]
WantedBy=multi-user.target
EOF
echo_cyan "[+] Create PHP-FPM 8.5 service..."
cat > /etc/systemd/system/php85-fpm.service << 'EOF'
[Unit]
Description=The PHP 8.5 FastCGI Process Manager
After=network.target
[Service]
Type=notify
UMask=0027
User=php
Group=php
RuntimeDirectory=php85-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/85/sbin/php-fpm --nodaemonize --fpm-config /server/etc/php/85/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
ExecStop=/bin/kill -SIGQUIT $MAINPID
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=60s
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536
TasksMax=1024
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/php/85 /run/php85-fpm /www /server/logs/php
[Install]
WantedBy=multi-user.target
EOF
echo_cyan "[+] Create Nginx service..."
cat > /etc/systemd/system/nginx.service << EOF
[Unit]
Description=nginx-1.28.x
After=network.target
[Service]
Type=forking
UMask=0027
User=nginx
Group=nginx
AmbientCapabilities=CAP_NET_BIND_SERVICE
RuntimeDirectory=nginx
RuntimeDirectoryMode=0750
ExecStartPre=/server/nginx/sbin/nginx -t -c /server/etc/nginx/nginx.conf
ExecStart=/server/nginx/sbin/nginx -c /server/etc/nginx/nginx.conf
ExecReload=/server/nginx/sbin/nginx -s reload
ExecStop=/server/nginx/sbin/nginx -s quit
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=30s
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/nginx/ /run/nginx/ /server/logs/nginx
[Install]
WantedBy=multi-user.target
EOF
echo_cyan "[+] Create MySQL service..."
cat > /etc/systemd/system/mysqld-84.service << EOF
[Unit]
Description=MySQL database server
Documentation=man:mysqld(8)
After=network-online.target
Wants=network-online.target
After=syslog.target
[Service]
Type=notify
UMask=0027
User=mysql
Group=mysql
RuntimeDirectory=mysql
RuntimeDirectoryMode=0750
ExecStart=/server/mysql/bin/mysqld --defaults-file=/server/etc/mysql/my.cnf
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=120s
TimeoutStartSec=infinity
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536
LimitNPROC=65536
LimitMEMLOCK=infinity
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/mysql /run/mysql /server/data /server/logs/mysql
[Install]
WantedBy=multi-user.target
EOF
echo_green "Registered Service..."
systemctl daemon-reload
systemctl enable --now {redis,postgres,php85-fpm,nginx,mysqld-84}.service
}
#日志管理
LogManagement(){
echo_yellow "=================================================================="
echo_green "Redis 和 Nginx 使用 Logrotate 来管理日志文件"
echo_yellow "=================================================================="
echo_cyan "[+] 创建 redis 的 Logrotate 脚本..."
cat > /etc/logrotate.d/redis << 'EOF'
/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
}
EOF
echo_cyan "[+] 创建 nginx 的 Logrotate 脚本..."
cat > /etc/logrotate.d/nginx << 'EOF'
/server/logs/nginx/access/*.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
}
/server/logs/nginx/error/*.log {
monthly
maxsize 100M
missingok
rotate 12
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
}
EOF
}
#PHP工具软链接到 /usr/local/bin
PhpToolsManagement(){
echo_yellow "=================================================================="
echo_green "PHP工具软链接到 /usr/local/bin"
echo_green "含:composer和php-cs-fixer"
echo_yellow "=================================================================="
ln -s /server/etc/php/tools/composer.phar /usr/local/bin/composer
ln -s /server/etc/php/tools/php-cs-fixer-v3.phar /usr/local/bin/php-cs-fixer
}
#安装nginx站点管理工具
InstallSiteManagement(){
echo_yellow "=================================================================="
echo_green "安装nginx站点管理工具"
echo_yellow "=================================================================="
echo_cyan "[+] 创建nginx站点管理工具..."
cat > /usr/local/bin/nginxctl << 'EOF'
#!/usr/bin/env bash
# ==============================================
# nginxctl - Nginx 站点管理工具
# 功能: 启用/禁用 Nginx 站点配置
# 作者: 地上马
# ==============================================
# 定义路径
AVAILABLE_DIR="/server/sites/available"
ENABLED_DIR="/server/sites/enabled"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 打印带格式的消息函数
print_success() {
echo -e "${GREEN}[SUCCESS] $1${NC}"
}
print_error() {
echo -e "${RED}[ERROR] $1${NC}"
}
print_info() {
echo -e "${BLUE}[INFO] $1${NC}"
}
print_warning() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
# 检查必要目录是否存在
check_directories() {
if [ ! -d "$AVAILABLE_DIR" ]; then
print_error "目录不存在: $AVAILABLE_DIR"
exit 1
fi
if [ ! -d "$ENABLED_DIR" ]; then
print_error "目录不存在: $ENABLED_DIR"
exit 1
fi
}
# 执行启用操作
enable_site() {
local SITE_NAME=$1
local CONF_FILE="${SITE_NAME}.nginx"
local AVAILABLE_FILE="${AVAILABLE_DIR}/${CONF_FILE}"
local ENABLED_FILE="${ENABLED_DIR}/${CONF_FILE}"
# 检查可用配置文件是否存在
if [ ! -f "$AVAILABLE_FILE" ]; then
print_error "配置文件 ${AVAILABLE_FILE} 不存在"
exit 1
fi
# 检查是否已启用
if [ -L "$ENABLED_FILE" ]; then
print_warning "站点 ${SITE_NAME} 已启用,无需重复操作"
exit 0
fi
# 创建软链接
if ! ln -s "$AVAILABLE_FILE" "$ENABLED_FILE"; then
print_error "创建软链接失败"
exit 1
fi
print_success "已启用站点 ${SITE_NAME}"
# 测试Nginx配置
print_info "测试Nginx配置..."
if ! nginx -t; then
print_error "Nginx 配置测试失败,请检查配置"
exit 1
fi
# 重载nginx
print_info "重载Nginx配置..."
if ! systemctl reload nginx; then
print_error "重载Nginx失败"
exit 1
fi
print_success "Nginx已成功重载"
}
# 执行禁用操作
disable_site() {
local SITE_NAME=$1
local CONF_FILE="${SITE_NAME}.nginx"
local ENABLED_FILE="${ENABLED_DIR}/${CONF_FILE}"
# 检查是否已启用
if [ ! -L "$ENABLED_FILE" ]; then
print_warning "站点 ${SITE_NAME} 未启用,无需操作"
exit 0
fi
# 删除软链接
if ! rm "$ENABLED_FILE"; then
print_error "删除软链接失败"
exit 1
fi
print_success "已禁用站点 ${SITE_NAME}"
# 测试Nginx配置
print_info "测试Nginx配置..."
if ! nginx -t; then
print_error "Nginx 配置测试失败,请检查配置"
exit 1
fi
# 重载nginx
print_info "重载Nginx配置..."
if ! systemctl reload nginx; then
print_error "重载Nginx失败"
exit 1
fi
print_success "Nginx已成功重载"
}
# 显示帮助信息
show_help() {
echo -e "${BLUE}nginxctl - Nginx站点管理工具${NC}"
echo ""
echo -e "${BLUE}用法:${NC}"
echo -e " nginxctl enable <site_name> ${GREEN}启用指定站点${NC}"
echo -e " nginxctl disable <site_name> ${RED}禁用指定站点${NC}"
echo -e " nginxctl help ${BLUE}显示帮助信息${NC}"
echo ""
echo -e "${BLUE}示例:${NC}"
echo -e " ${GREEN}nginxctl enable demo${NC}"
echo -e " ${RED}nginxctl disable demo${NC}"
echo ""
echo -e "${BLUE}说明:${NC}"
echo -e " 站点配置文件应位于 ${AVAILABLE_DIR}/ 目录中"
echo -e " 启用后会在 ${ENABLED_DIR}/ 创建软链接"
}
# 主程序逻辑
main() {
# 检查必要目录是否存在
check_directories
# 检查参数数量
if [ $# -lt 1 ]; then
show_help
exit 1
fi
ACTION=$1
SITE_NAME=$2
# 根据输入参数执行相应操作
case "$ACTION" in
enable)
if [ $# -ne 2 ]; then
print_error "启用站点需要指定站点名称"
echo "用法: nginxctl enable <site_name>"
exit 1
fi
enable_site "$SITE_NAME"
;;
disable)
if [ $# -ne 2 ]; then
print_error "禁用站点需要指定站点名称"
echo "用法: nginxctl disable <site_name>"
exit 1
fi
disable_site "$SITE_NAME"
;;
help|--help|-h)
show_help
;;
*)
print_error "无效操作 '${ACTION}'"
echo "可用操作: enable, disable"
echo "使用 'nginxctl help' 查看完整帮助"
exit 1
;;
esac
}
# 执行主程序
main "$@"
EOF
echo_cyan "站点管理工具授权..."
chown nginx:nginx /usr/local/bin/nginxctl
chmod 750 /usr/local/bin/nginxctl
}
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 ' '
#解压lnpp预构建包到指定目录
InstallBuild
echo ' '
#是否重新生成tls证书
echo_cyan "是否重置数字证书(1重置/默认不重置):"
read isResetCertificate
if [[ "$isResetCertificate" == '1' ]]; then
resetRedisCertificate
resetPgsqlCertificate
fi
echo ' '
#修改文件权限
modFilePower
echo ' '
#安装systemctl单元
InstallSystemctlUnit
#PHP工具软链接到 /usr/local/bin
PhpToolsManagement
#安装nginx站点管理工具
InstallSiteManagement
echo ' '
echo_yellow "=================================================================="
echo_green "lnmpp安装完成"
echo_yellow " - Postgres 默认有个超级管理员用户 admin 密码 1"
echo_yellow " - MySQL 默认有超级管理员用户 admin@190.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,postgres,php85-fpm,nginx,mysqld-84}.service"
echo_yellow "禁用并禁止服务"
echo_yellow "systemctl disable --now {redis,postgres,php85-fpm,nginx,mysqld-84}.service"
echo_yellow "开启"
echo_yellow "systemctl start {redis,postgres,php85-fpm,nginx,mysqld-84}.service"
echo_yellow "停止"
echo_yellow "systemctl stop {redis,postgres,php85-fpm,nginx,mysqld-84}.service"
echo_yellow "查看状态"
echo_yellow "systemctl status {redis,postgres,php85-fpm,nginx,mysqld-84}.service"
echo_yellow "重新加载配置(部分服务器不支持重载配置文件)"
echo_yellow "systemctl reload nginx"
echo_yellow "使用nginx站点管理工具"
echo_yellow "启用站点: nginxctl enable <site_name>"
echo_yellow "禁用站点: nginxctl disable <site_name>"
echo_yellow "获取帮助: nginxctl help"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_red "条件允许,建议重启系统!!!"
echo_yellow "=================================================================="
fish
#!/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,php85-fpm,nginx}.service
rm /lib/systemd/system/{redis,postgres,php85-fpm,nginx}.service
rm /etc/systemd/system/{redis,postgres,php85-fpm,nginx}.service
systemctl daemon-reload
echo_cyan "清理旧目录 /server,/www 如果有重要数据请先备份"
rm -rf /server /www
echo_cyan "删除旧的 SQLite3,Redis,PostgreSQL,PHP,Nginx 进程用户"
userdel -r sqlite3
userdel -r redis
userdel -r postgres
userdel -r php
userdel -r nginx
groupdel sqlite3
groupdel redis
groupdel postgres
groupdel php
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/.zshrc /home/$userName
ln -s /server/ohmyzsh/ /home/$userName
chown $userName:$userName /home/$userName/.zshrc
fi
}
#创建用户
createUser(){
echo_yellow "=================================================================="
echo_green "创建 SQLite3,Redis,PostgreSQL,PHP,Nginx 的进程用户"
echo_yellow "=================================================================="
echo_red "必须root用户安装并配置成功zsh,才允许支持zsh"
zshState=0
echo_cyan "是否支持启用zsh(1支持,默认不支持):"
read zshState
createSingleUser 'sqlite3' $zshState
createSingleUser 'redis' $zshState
createSingleUser 'postgres' $zshState
createSingleUser 'php' $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:nginx 660 \n(nginx 权限较少,php-fpm 权限较多)"
echo_cyan "usermod -a -G nginx php"
echo_yellow " "
echo_yellow "方式2:采用 sock 文件权限 php:php 660 \n(nginx 权限较多,php 权限较少)"
echo_cyan "usermod -a -G php nginx"
echo_yellow " "
echo_green "此版本使用的是tcp转发,并不需要考虑socket文件转发相关的权限问题"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_green "php编译pgsql扩展,使用指定PostgreSQL安装目录时,需要提供读取libpq相关权限:"
echo_green "php编译sqlite3扩展,使用指定sqlite3自带的pkgconfig时,需要提供读取对应目录的权限:"
echo_cyan "usermod -a -G sqlite3,postgres php"
echo_green "如果使用 apt install libpq-dev libsqlite3-dev -y 依赖包则不需要"
echo_yellow " "
echo_green "此版本PHP使用指定Postgres安装目录并在编译时禁用了sqlite3扩展"
echo_yellow "=================================================================="
usermod -a -G sqlite3,postgres php
}
#开发用户追加权限
devUserPower(){
devUserName=$1
echo_yellow "=================================================================="
echo_green "开发用户追加权限"
echo_yellow "WEB/PHP文件所属用户都是开发用户,所以nginx和php用户需要追加开发组"
echo_yellow " "
echo_red "部署环境请注释此函数,开发环境需要开启"
echo_red "部署环境不需要开发用户,可直接使用 nginx 用户作为 ftp、ssh 等上传工具的用户"
echo_yellow "=================================================================="
usermod -a -G $devUserName nginx
usermod -a -G $devUserName php
usermod -a -G sqlite3,redis,postgres,php,nginx $devUserName
}
#安装依赖包
installPackage(){
echo_yellow "=================================================================="
echo_green "安装依赖"
echo_green "确保 SQLite3/Redis/PostgreSQL/PHP/Nginx/MySQL 必备依赖项"
echo_green "debian13 发行版,如因依赖导致部分功能异常,自行安装相应依赖包即可"
echo_red "注意1:该lnpp包不兼容其他发行版,因为极有可能因为依赖问题,导致整个环境无法使用"
echo_red "注意2:部分依赖包在部署阶段可能没用,但由于没对单个功能测试,只能选择安装全部依赖"
echo_yellow "=================================================================="
apt install --no-install-recommends \
build-essential autoconf pkg-config \
tcl \
libsystemd-dev libssl-dev \
llvm-dev clang libicu-dev liblz4-dev libzstd-dev liburing-dev \
bison flex libreadline-dev zlib1g-dev uuid-dev \
libcurl4-openssl-dev libpng-dev libjpeg-dev libfreetype-dev \
libonig-dev libsodium-dev libargon2-dev \
libxslt1-dev libgd-dev libgeoip-dev \
-y
}
#安装预构建包
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(){
redisTlsScriptPath=/server/etc/redis/gen-test-certs.sh
rm -rf /server/etc/redis/tls
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..."
cat > $redisTlsScriptPath << 'EOF'
#!/bin/bash
# Generate some test certificates which are used by the regression test suite:
#
# tests/tls/ca.{crt,key} Self signed CA certificate.
# tests/tls/redis.{crt,key} A certificate with no key usage/policy restrictions.
# tests/tls/client.{crt,key} A certificate restricted for SSL client usage.
# tests/tls/server.{crt,key} A certificate restricted for SSL server usage.
# tests/tls/redis.dh DH Params file.
redisTlsPath=/server/etc/redis/tls
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
}
[ -d $redisTlsPath ] || 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
EOF
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(){
pgsqlTlsScriptPath=/server/etc/postgres/gen-test-certs.sh
rm -rf /server/etc/postgres/tls
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..."
cat > $pgsqlTlsScriptPath << 'EOF'
#!/bin/bash
# 这些文件是用于生成测试证书的,部署环境应从正规的数字证书的签发机构获取相关证书
#
# tls/root.{crt,key} CA证书用于签署其他证书,以建立信任链
# tls/pgsql.{crt,key} 这个证书可用于SSL/TLS连接中的任何用途
# tls/server.{crt,key} 只能用于SSL/TLS连接中的服务器身份验证
# tls/client.{crt,key} 只能用于SSL/TLS连接中的客户端身份验证
# tls/client-emad.{crt,key} 允许用户emad使用verify-full验证类型
# tls/client-admin.{crt,key} 允许用户admin使用verify-full验证类型
# tls/pgsql.dh 在SSL/TLS握手过程中协商临时密钥,以确保通信的安全性
pgsqlTlsPath=/server/etc/postgres/tls
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
}
[ -d $pgsqlTlsPath ] || 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-replication "repl_user" "-extfile $pgsqlTlsPath/openssl.cnf -extensions client_cert"
generate_cert pgsql "Generic-cert"
[ -f $pgsqlTlsPath/pgsql.dh ] || openssl dhparam -out $pgsqlTlsPath/pgsql.dh 2048
EOF
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 需加入 emad用户组)"
echo_red "部署环境通常是www用户(nginx/php 需加入 www用户组)"
chmod 750 /www
echo_green "ohmyzsh文件权限"
chown root:root -R /server/ohmyzsh
find /server/ohmyzsh -type f -exec chmod 644 {} \;
find /server/ohmyzsh -type d -exec chmod 755 {} \;
echo_green "SQLite3文件权限"
chown sqlite3:sqlite3 -R /server/sqlite3
find /server/sqlite3 -type f -exec chmod 640 {} \;
find /server/sqlite3 -type d -exec chmod 750 {} \;
chmod 750 -R /server/sqlite3/bin
echo_green "Redis文件权限"
chown redis:redis -R /server/redis /server/logs/redis /server/etc/redis
find /server/redis /server/logs/redis /server/etc/redis -type f -exec chmod 640 {} \;
find /server/redis /server/logs/redis /server/etc/redis -type d -exec chmod 750 {} \;
chmod 750 -R /server/redis/bin
find /server/etc/redis/tls -type f -exec chmod 600 {} \;
find /server/etc/redis/tls -type d -exec chmod 700 {} \;
echo_green "PostgreSQL文件权限"
chown postgres:postgres -R /server/postgres /server/pgData /server/logs/postgres /server/etc/postgres
find /server/postgres /server/logs/postgres /server/etc/postgres -type f -exec chmod 640 {} \;
find /server/postgres /server/logs/postgres /server/etc/postgres -type d -exec chmod 750 {} \;
chmod 750 -R /server/postgres/bin
find /server/etc/postgres/tls /server/pgData -type f -exec chmod 600 {} \;
find /server/etc/postgres/tls /server/pgData -type d -exec chmod 700 {} \;
echo_green "PHP文件权限"
chown php:php -R /server/php /server/logs/php /server/etc/php
find /server/php /server/logs/php /server/etc/php -type f -exec chmod 640 {} \;
find /server/php /server/logs/php /server/etc/php -type d -exec chmod 750 {} \;
chmod 750 /server/etc/php/tools/{composer,php-cs-fixer-v3}.phar
chmod 750 -R /server/php/85/{bin,sbin}
chmod 640 /server/php/85/lib/php/extensions/no-debug-non-zts-*/*
echo_green "Nginx文件权限"
chown nginx:nginx -R /server/{nginx,sites}
chown nginx:nginx -R /server/{etc,logs}/nginx
find /server/{nginx,sites} -type f -exec chmod 640 {} \;
find /server/{nginx,sites} -type d -exec chmod 750 {} \;
find /server/{etc,logs}/nginx -type f -exec chmod 640 {} \;
find /server/{etc,logs}/nginx -type d -exec chmod 750 {} \;
find /server/sites/tls -type f -exec chmod 600 {} \;
chmod 750 /server/nginx/sbin/nginx
}
#安装systemctl单元
InstallSystemctlUnit(){
echo_yellow "=================================================================="
echo_green "加入systemctl守护进程\n含systemctl unit文件"
echo_yellow " "
echo_cyan "/lib/systemd/system/{redis,postgres,php85-fpm,nginx}.service"
echo_yellow " "
echo_green "支持开启自动启动服务,非常规终止进程会自动启动服务"
echo_yellow "=================================================================="
echo_cyan "[+] Create Redis service..."
cat > /etc/systemd/system/redis.service << 'EOF'
[Unit]
Description=Redis In-Memory Data Store
After=network.target
[Service]
Type=notify
UMask=0027
User=redis
Group=redis
RuntimeDirectory=redis
RuntimeDirectoryMode=0750
ExecStart=/server/redis/bin/redis-server /server/etc/redis/config/redis.conf
ExecReload=/bin/kill -s HUP $MAINPID
ExecStop=/server/redis/bin/redis-cli shutdown
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=60s
Restart=on-failure
RestartSec=10s
LimitNOFILE=10000
LimitNPROC=10000
LimitMEMLOCK=infinity
LimitAS=infinity
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/redis /run/redis /server/logs/redis
[Install]
WantedBy=multi-user.target
EOF
echo_cyan "[+] Create PostgreSQL service..."
cat > /etc/systemd/system/postgres.service << 'EOF'
[Unit]
Description=PostgreSQL database server
Documentation=man:postgres(1)
After=network-online.target
Wants=network-online.target
[Service]
Type=notify
UMask=0027
User=postgres
Group=postgres
RuntimeDirectory=postgres
RuntimeDirectoryMode=0750
ExecStart=/server/postgres/bin/postgres -D /server/pgData
ExecReload=/bin/kill -HUP $MAINPID
ExecReload=/server/postgres/bin/pg_ctl reload
ExecStop=/server/postgres/bin/pg_ctl -D /server/pgData stop -m smart
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=120s
TimeoutStartSec=infinity
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536
LimitNPROC=65536
LimitMEMLOCK=infinity
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/postgres /run/postgres /server/pgData /server/logs/postgres
[Install]
WantedBy=multi-user.target
EOF
echo_cyan "[+] Create PHP-FPM 8.5 service..."
cat > /etc/systemd/system/php85-fpm.service << 'EOF'
[Unit]
Description=The PHP 8.5 FastCGI Process Manager
After=network.target
[Service]
Type=notify
UMask=0027
User=php
Group=php
RuntimeDirectory=php85-fpm
RuntimeDirectoryMode=0750
ExecStart=/server/php/85/sbin/php-fpm --nodaemonize --fpm-config /server/etc/php/85/php-fpm.conf
ExecReload=/bin/kill -USR2 $MAINPID
ExecStop=/bin/kill -SIGQUIT $MAINPID
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=60s
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536
TasksMax=1024
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/php/85 /run/php85-fpm /www /server/logs/php
[Install]
WantedBy=multi-user.target
EOF
echo_cyan "[+] Create Nginx service..."
cat > /etc/systemd/system/nginx.service << EOF
[Unit]
Description=nginx-1.28.x
After=network.target
[Service]
Type=forking
UMask=0027
User=nginx
Group=nginx
AmbientCapabilities=CAP_NET_BIND_SERVICE
RuntimeDirectory=nginx
RuntimeDirectoryMode=0750
ExecStartPre=/server/nginx/sbin/nginx -t -c /server/etc/nginx/nginx.conf
ExecStart=/server/nginx/sbin/nginx -c /server/etc/nginx/nginx.conf
ExecReload=/server/nginx/sbin/nginx -s reload
ExecStop=/server/nginx/sbin/nginx -s quit
KillMode=mixed
KillSignal=SIGTERM
TimeoutStopSec=30s
Restart=on-failure
RestartSec=10s
LimitNOFILE=65536
NoNewPrivileges=true
PrivateTmp=true
PrivateDevices=true
ProtectSystem=strict
ProtectHome=true
ProtectHostname=true
ProtectClock=true
ProtectKernelTunables=true
ProtectKernelModules=true
ProtectKernelLogs=true
ProtectControlGroups=true
RestrictRealtime=true
RestrictNamespaces=true
RestrictAddressFamilies=AF_INET AF_INET6 AF_NETLINK AF_UNIX
ReadWritePaths=/server/nginx/ /run/nginx/ /server/logs/nginx
[Install]
WantedBy=multi-user.target
EOF
echo_green "Registered Service..."
systemctl daemon-reload
systemctl enable --now {redis,postgres,php85-fpm,nginx}.service
}
#日志管理
LogManagement(){
echo_yellow "=================================================================="
echo_green "Redis 和 Nginx 使用 Logrotate 来管理日志文件"
echo_yellow "=================================================================="
echo_cyan "[+] 创建 redis 的 Logrotate 脚本..."
cat > /etc/logrotate.d/redis << 'EOF'
/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
}
EOF
echo_cyan "[+] 创建 nginx 的 Logrotate 脚本..."
cat > /etc/logrotate.d/nginx << 'EOF'
/server/logs/nginx/access/*.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
}
/server/logs/nginx/error/*.log {
monthly
maxsize 100M
missingok
rotate 12
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
}
EOF
}
#PHP工具软链接到 /usr/local/bin
PhpToolsManagement(){
echo_yellow "=================================================================="
echo_green "PHP工具软链接到 /usr/local/bin"
echo_green "含:composer和php-cs-fixer"
echo_yellow "=================================================================="
ln -s /server/etc/php/tools/composer.phar /usr/local/bin/composer
ln -s /server/etc/php/tools/php-cs-fixer-v3.phar /usr/local/bin/php-cs-fixer
}
#安装nginx站点管理工具
InstallSiteManagement(){
echo_yellow "=================================================================="
echo_green "安装nginx站点管理工具"
echo_yellow "=================================================================="
echo_cyan "[+] 创建nginx站点管理工具..."
cat > /usr/local/bin/nginxctl << 'EOF'
#!/usr/bin/env bash
# ==============================================
# nginxctl - Nginx 站点管理工具
# 功能: 启用/禁用 Nginx 站点配置
# 作者: 地上马
# ==============================================
# 定义路径
AVAILABLE_DIR="/server/sites/available"
ENABLED_DIR="/server/sites/enabled"
# 颜色定义
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
BLUE='\033[0;34m'
NC='\033[0m' # No Color
# 打印带格式的消息函数
print_success() {
echo -e "${GREEN}[SUCCESS] $1${NC}"
}
print_error() {
echo -e "${RED}[ERROR] $1${NC}"
}
print_info() {
echo -e "${BLUE}[INFO] $1${NC}"
}
print_warning() {
echo -e "${YELLOW}[WARNING] $1${NC}"
}
# 检查必要目录是否存在
check_directories() {
if [ ! -d "$AVAILABLE_DIR" ]; then
print_error "目录不存在: $AVAILABLE_DIR"
exit 1
fi
if [ ! -d "$ENABLED_DIR" ]; then
print_error "目录不存在: $ENABLED_DIR"
exit 1
fi
}
# 执行启用操作
enable_site() {
local SITE_NAME=$1
local CONF_FILE="${SITE_NAME}.nginx"
local AVAILABLE_FILE="${AVAILABLE_DIR}/${CONF_FILE}"
local ENABLED_FILE="${ENABLED_DIR}/${CONF_FILE}"
# 检查可用配置文件是否存在
if [ ! -f "$AVAILABLE_FILE" ]; then
print_error "配置文件 ${AVAILABLE_FILE} 不存在"
exit 1
fi
# 检查是否已启用
if [ -L "$ENABLED_FILE" ]; then
print_warning "站点 ${SITE_NAME} 已启用,无需重复操作"
exit 0
fi
# 创建软链接
if ! ln -s "$AVAILABLE_FILE" "$ENABLED_FILE"; then
print_error "创建软链接失败"
exit 1
fi
print_success "已启用站点 ${SITE_NAME}"
# 测试Nginx配置
print_info "测试Nginx配置..."
if ! nginx -t; then
print_error "Nginx 配置测试失败,请检查配置"
exit 1
fi
# 重载nginx
print_info "重载Nginx配置..."
if ! systemctl reload nginx; then
print_error "重载Nginx失败"
exit 1
fi
print_success "Nginx已成功重载"
}
# 执行禁用操作
disable_site() {
local SITE_NAME=$1
local CONF_FILE="${SITE_NAME}.nginx"
local ENABLED_FILE="${ENABLED_DIR}/${CONF_FILE}"
# 检查是否已启用
if [ ! -L "$ENABLED_FILE" ]; then
print_warning "站点 ${SITE_NAME} 未启用,无需操作"
exit 0
fi
# 删除软链接
if ! rm "$ENABLED_FILE"; then
print_error "删除软链接失败"
exit 1
fi
print_success "已禁用站点 ${SITE_NAME}"
# 测试Nginx配置
print_info "测试Nginx配置..."
if ! nginx -t; then
print_error "Nginx 配置测试失败,请检查配置"
exit 1
fi
# 重载nginx
print_info "重载Nginx配置..."
if ! systemctl reload nginx; then
print_error "重载Nginx失败"
exit 1
fi
print_success "Nginx已成功重载"
}
# 显示帮助信息
show_help() {
echo -e "${BLUE}nginxctl - Nginx站点管理工具${NC}"
echo ""
echo -e "${BLUE}用法:${NC}"
echo -e " nginxctl enable <site_name> ${GREEN}启用指定站点${NC}"
echo -e " nginxctl disable <site_name> ${RED}禁用指定站点${NC}"
echo -e " nginxctl help ${BLUE}显示帮助信息${NC}"
echo ""
echo -e "${BLUE}示例:${NC}"
echo -e " ${GREEN}nginxctl enable demo${NC}"
echo -e " ${RED}nginxctl disable demo${NC}"
echo ""
echo -e "${BLUE}说明:${NC}"
echo -e " 站点配置文件应位于 ${AVAILABLE_DIR}/ 目录中"
echo -e " 启用后会在 ${ENABLED_DIR}/ 创建软链接"
}
# 主程序逻辑
main() {
# 检查必要目录是否存在
check_directories
# 检查参数数量
if [ $# -lt 1 ]; then
show_help
exit 1
fi
ACTION=$1
SITE_NAME=$2
# 根据输入参数执行相应操作
case "$ACTION" in
enable)
if [ $# -ne 2 ]; then
print_error "启用站点需要指定站点名称"
echo "用法: nginxctl enable <site_name>"
exit 1
fi
enable_site "$SITE_NAME"
;;
disable)
if [ $# -ne 2 ]; then
print_error "禁用站点需要指定站点名称"
echo "用法: nginxctl disable <site_name>"
exit 1
fi
disable_site "$SITE_NAME"
;;
help|--help|-h)
show_help
;;
*)
print_error "无效操作 '${ACTION}'"
echo "可用操作: enable, disable"
echo "使用 'nginxctl help' 查看完整帮助"
exit 1
;;
esac
}
# 执行主程序
main "$@"
EOF
echo_cyan "站点管理工具授权..."
chown nginx:nginx /usr/local/bin/nginxctl
chmod 750 /usr/local/bin/nginxctl
}
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 "部署环境通常不需要授权"
echo_cyan "输入开发用户名,为其授权(为空不授权):"
read userName
if [[ -n "$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
#PHP工具软链接到 /usr/local/bin
PhpToolsManagement
#安装nginx站点管理工具
InstallSiteManagement
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,php85-fpm,nginx}.service"
echo_yellow "禁用并禁止服务"
echo_yellow "systemctl disable --now {redis,postgres,php85-fpm,nginx}.service"
echo_yellow "开启"
echo_yellow "systemctl start {redis,postgres,php85-fpm,nginx}.service"
echo_yellow "停止"
echo_yellow "systemctl stop {redis,postgres,php85-fpm,nginx}.service"
echo_yellow "查看状态"
echo_yellow "systemctl status {redis,postgres,php85-fpm,nginx}.service"
echo_yellow "重新加载配置(部分服务器不支持重载配置文件)"
echo_yellow "systemctl reload nginx"
echo_yellow "使用nginx站点管理工具"
echo_yellow "启用站点: nginxctl enable <site_name>"
echo_yellow "禁用站点: nginxctl disable <site_name>"
echo_yellow "获取帮助: nginxctl help"
echo_yellow "=================================================================="
echo ' '
echo_yellow "=================================================================="
echo_red "条件允许,建议重启系统!!!"
echo_yellow "=================================================================="
fibash
# lnmpp一键安装
cd /
mv lnmpp-*.tar.xz lnmpp.tar.xz
chmod +x lnmpp-setup.sh
./lnmpp-setup.sh
# lnpp一键安装
cd /
mv lnpp-*.tar.xz lnpp.tar.xz
chmod +x lnpp-setup.sh
./lnpp-setup.sh附录:时区设为东八区
bash
timedatectl set-timezone Asia/Shanghai