AD域控&LDAP在线密码修改及自助找回密码开源平台(Self Service Password 一键安装脚本使用说明)
Self Service Password (SSP) 是一款专为LDAP/AD环境设计的开源密码自助服务系统,支持密码重置、修改和多因素认证等功能。本文介绍了一个针对Debian 12系统优化的SSP一键安装脚本,提供全新安装、升级和重新安装等多种模式,自动处理依赖和配置问题。脚本支持本地安装包检测、错误自动修复和安全配置生成,并包含Apache优化设置。安装过程涵盖环境检查、依赖安装、SSP部
📋 概述
这是一个专为 Debian 12 系统设计的 Self Service Password (SSP) 一键安装脚本,基于实际部署经验优化,能够自动处理各种常见问题并提供多种安装模式。
版本: V1.0
作者: 大刘讲IT 微信公众号同号
最后更新: 2025年6月
注: 配置文件config.inc.php是一个相当重要的文件,需要了解基本的ldap配置和邮件配置;自助链接密码找回需要配置启用邮件,AD或ldap需要mail字段需要配置好邮件地址。
🌟 Self Service Password 功能介绍
什么是 Self Service Password?
Self Service Password (SSP) 是一个开源的企业级密码自助服务系统,专为 LDAP/Active Directory 环境设计。它允许用户在无需管理员干预的情况下,自主完成密码重置、修改等操作,大大减轻了IT管理员的工作负担。
🔑 核心功能
密码管理功能
- 🔐 密码重置:用户忘记密码时可通过邮件、短信等方式自助重置
- 🔄 密码修改:已登录用户可直接修改当前密码
- 📊 密码策略:支持复杂密码策略配置和实时验证
- ⏰ 密码过期提醒:主动提醒用户密码即将过期
身份验证方式
- 📧 邮件验证:通过邮件发送重置链接或验证码
- 📱 短信验证:支持SMS短信验证码验证
- ❓ 安全问题:预设安全问题验证身份
- 🔢 CAPTCHA:防止恶意攻击的图形验证码
- 🎫 令牌验证:支持时间限制的安全令牌
目录服务支持
- 🏢 Active Directory:完整支持微软AD环境
- 🐧 OpenLDAP:支持各种OpenLDAP部署
- 🌐 LDAPS/StartTLS:支持加密连接保障安全
- 🔗 多域支持:可同时管理多个LDAP域
🎨 用户界面特性
多语言支持
- 🌍 国际化:支持30+种语言界面
- 🇨🇳 中文界面:完整的简体中文支持
- 🎨 主题定制:可自定义界面主题和样式
- 📱 响应式设计:支持桌面、平板、手机等设备
用户体验
- ✨ 直观界面:简洁明了的操作界面
- 🚀 快速操作:几步即可完成密码重置
- 💡 智能提示:实时密码强度提示和格式验证
- 🔍 搜索功能:管理员可快速查找用户
🛡️ 安全特性
安全防护
- 🔒 加密传输:支持HTTPS加密通信
- 🛡️ 防暴力破解:登录尝试次数限制和锁定机制
- 📝 审计日志:详细记录所有操作日志
- 🚫 IP限制:支持IP白名单和黑名单
- ⏱️ 会话管理:安全的会话超时和管理
密码安全
- 📏 复杂度要求:可配置密码长度、字符类型要求
- 📚 历史检查:防止重复使用历史密码
- 🚫 弱密码检测:内置常见弱密码字典
- 🔄 强制更新:支持强制密码更新策略
🔧 管理功能
系统管理
- ⚙️ 配置管理:Web界面配置系统参数
- 📊 统计报表:密码重置统计和用户活动报表
- 👥 用户管理:批量用户操作和权限管理
- 🔔 通知系统:邮件和短信通知配置
集成能力
- 🔌 API接口:RESTful API支持第三方集成
- 📧 邮件系统:支持SMTP、Exchange等邮件系统
- 📱 短信网关:集成各种短信服务提供商
- 🔗 SSO集成:支持单点登录系统集成
📈 企业级特性
高可用性
- ⚡ 负载均衡:支持多实例负载均衡部署
- 💾 数据备份:配置和日志数据备份机制
- 🔄 故障恢复:快速故障检测和恢复
- 📊 性能监控:系统性能指标监控
合规性
- 📋 审计合规:满足企业审计要求
- 🔐 数据保护:符合GDPR等数据保护法规
- 📝 操作记录:完整的操作审计轨迹
- 🛡️ 安全标准:遵循企业安全最佳实践
🎯 适用场景
企业环境
- 🏢 中大型企业:员工自助密码管理
- 🏫 教育机构:学生和教职工密码服务
- 🏥 医疗机构:医护人员密码管理
- 🏭 制造业:工厂员工密码自助服务
技术环境
- 🖥️ 混合环境:Windows/Linux混合环境
- ☁️ 云端部署:支持云服务器部署
- 🏠 本地部署:内网环境独立部署
- 🔗 混合云:混合云环境统一管理
💰 成本效益
降低成本
- ⏰ 减少工单:大幅减少密码重置工单数量
- 👨💼 节省人力:减轻IT管理员工作负担
- 📞 减少呼叫:降低IT服务台电话咨询
- 🚀 提高效率:用户可立即解决密码问题
提升体验
- ✅ 24/7可用:全天候自助服务
- ⚡ 即时解决:无需等待IT支持
- 🎯 精准定位:快速定位和解决问题
- 😊 用户满意:显著提升用户满意度
🎯 主要特性
- ✅ 智能安装模式:支持全新安装、升级、重新安装等多种模式
- ✅ 本地安装包支持:自动检测脚本目录中的安装包,无需网络下载
- ✅ 错误自动修复:智能检测并修复配置文件语法错误
- ✅ 非中断安装:配置文件问题不会阻止安装继续进行
- ✅ 完整依赖管理:自动安装和配置所有必需的软件包
- ✅ 安全配置:自动生成安全密钥和基本配置
- ✅ Apache 优化:根据官方文档配置 Apache 虚拟主机
🔧 环境要求
操作系统
- 推荐: Debian 12 (Bookworm) 全新安装
- 兼容: Ubuntu 20.04+ 或其他基于 Debian 的发行版
硬件要求
- CPU: 1 核心以上
- 内存: 1GB 以上
- 磁盘: 2GB 以上可用空间
- 网络: 能够访问软件源(用于安装依赖包)
权限要求
- 必须: root 用户或具有 sudo 权限的用户
- 推荐: 直接使用 root 用户执行
软件依赖
脚本会自动安装以下软件包,无需预先安装:
- Apache2 Web 服务器
- PHP 8.2 及相关扩展
- Composer PHP 包管理器
- 其他必需的系统工具
📦 安装包准备
下载 SSP 安装包
- 访问 SSP 官方发布页面
- 下载最新稳定版本的源码包
- 支持的格式:
.tar.gz
或.zip
推荐的文件名格式
self-service-password-1.6.tar.gz
self-service-password-latest.zip
ssp-1.6.tar.gz
文件放置
将下载的安装包放置在与安装脚本相同的目录中:
文档项目/
├── install_ssp.sh # 主安装脚本
├── self-service-password-1.6.tar.gz # SSP 安装包
├── fix_config_syntax.sh # 配置修复脚本(可选)
└── README_SSP安装脚本使用说明.md # 本说明文档
🚀 安装步骤
1. 准备工作
# 确保以 root 用户身份登录
sudo su -
# 进入脚本目录
cd /path/to/script/directory
# 确认文件存在
ls -la install_ssp.sh self-service-password*.tar.gz
2. 赋予执行权限
chmod +x install_ssp.sh
chmod +x fix_config_syntax.sh # 可选
3. 运行安装脚本
交互式安装(推荐)
./install_ssp.sh
脚本会自动检测现有安装并询问您的选择。
非交互式安装
# 全新安装
./install_ssp.sh --force-fresh
# 升级现有安装
./install_ssp.sh --force-upgrade
# 完全重新安装
./install_ssp.sh --force-reinstall
# 指定安装目录
./install_ssp.sh --install-dir /opt/ssp
# 非交互模式
./install_ssp.sh --non-interactive
4. 查看帮助信息
./install_ssp.sh --help
📋 安装模式说明
🆕 全新安装 (fresh)
- 适用于全新的系统环境
- 安装所有依赖包和 SSP
- 创建全新的配置文件
🔄 升级模式 (upgrade)
- 保留现有配置文件
- 更新 SSP 代码和依赖
- 智能跳过已安装的系统组件
🗑️ 重新安装 (reinstall)
- 删除现有安装
- 备份重要配置文件
- 执行全新安装
📂 新位置安装 (new_location)
- 在新目录安装 SSP
- 不影响现有安装
- 适用于测试或多实例部署
🔧 安装过程详解
第1步:环境检查
- 检查操作系统兼容性
- 验证网络连接
- 检测现有安装状态
第2步:依赖安装
- 更新系统软件包
- 安装 Apache2 和 PHP 8.2
- 安装必需的 PHP 扩展
第3步:SSP 部署
- 解压安装包到指定目录
- 智能检测 SSP 源码结构
- 验证关键文件完整性
第4步:Composer 依赖
- 强制全新安装 PHP 依赖
- 自动检测并修复缺失的库
- 优化 autoload 配置
第5步:配置文件设置
- 生成安全的随机密钥
- 设置基本运行参数
- 智能修复语法错误
第6步:权限配置
- 设置正确的文件权限
- 创建必需的缓存目录
- 配置 Web 服务器用户权限
第7步:Apache 配置
- 创建专用虚拟主机
- 启用必需的 Apache 模块
- 配置安全访问规则
第8步:最终验证
- 验证所有服务状态
- 检查配置文件语法
- 创建诊断页面
🌐 访问和使用
安装完成后的访问地址
# 核心依赖检查页面
http://your-server-ip/install_check.php
# SSP 主页
http://your-server-ip/
# 本地访问
http://localhost/
首次配置
- 访问 SSP 主页
- 根据向导配置 LDAP/AD 连接
- 设置密码策略和安全选项
- 测试功能是否正常
🛠️ 故障排除
常见问题及解决方案
1. 配置文件语法错误
# 检查语法
php -l /var/www/html/ssp/conf/config.inc.php
# 自动修复
./fix_config_syntax.sh
# 手动修复第507行错误
vim /var/www/html/ssp/conf/config.inc.php
# 将 if (!define("SMARTY" 改为 if (!defined("SMARTY"))
2. Apache 服务问题
# 检查 Apache 状态
systemctl status apache2
# 重启 Apache
systemctl restart apache2
# 检查配置语法
apache2ctl configtest
# 查看错误日志
tail -f /var/log/apache2/ssp_error.log
3. PHP 依赖问题
# 重新安装 Composer 依赖
cd /var/www/html/ssp
rm -rf vendor composer.lock
composer install --no-dev
# 检查 autoload 文件
ls -la vendor/autoload.php
4. 权限问题
# 重新设置权限
chown -R www-data:www-data /var/www/html/ssp
chmod -R 755 /var/www/html/ssp
chmod -R 750 /var/www/html/ssp/conf
chmod -R 750 /var/www/html/ssp/cache
日志文件位置
- Apache 错误日志:
/var/log/apache2/ssp_error.log
- Apache 访问日志:
/var/log/apache2/ssp_access.log
- SSP 审计日志:
/var/log/apache2/ssp_audit.log
- 系统日志:
/var/log/syslog
配置文件位置
- 主配置文件:
/var/www/html/ssp/conf/config.inc.php
- Apache 配置:
/etc/apache2/sites-available/ssp.conf
- PHP 配置:
/etc/php/8.2/apache2/php.ini
📚 高级配置
LDAP 连接配置
安装完成后,您需要手动配置 LDAP 连接参数:
# 编辑配置文件
vim /var/www/html/ssp/conf/config.inc.php
# 添加 LDAP 配置
$ldap_url = "ldap://your-ldap-server:389";\\AD域控要使用ldaps,端口636(需要部署证书服务即可)
$ldap_binddn = "cn=admin,dc=example,dc=com";
$ldap_bindpw = "your-admin-password";
$ldap_base = "dc=example,dc=com";
SSL/HTTPS 配置
# 安装 Certbot
apt-get install certbot python3-certbot-apache
# 获取 SSL 证书
certbot --apache -d your-domain.com
# 自动续期
crontab -e
# 添加:0 12 * * * /usr/bin/certbot renew --quiet
性能优化
# 启用 PHP OPcache
vim /etc/php/8.2/apache2/php.ini
# 设置:opcache.enable=1
# 配置 Apache MPM
a2dismod mpm_prefork
a2enmod mpm_event
# 重启服务
systemctl restart apache2
🔒 安全建议
基本安全措施
- 定期更新:保持系统和 SSP 版本最新
- 强密码策略:配置复杂的密码要求
- 访问控制:限制管理界面访问
- 日志监控:定期检查访问和错误日志
- 备份策略:定期备份配置文件和数据
防火墙配置
# 安装 UFW
apt-get install ufw
# 基本规则
ufw allow ssh
ufw allow http
ufw allow https
ufw enable
📞 支持和反馈
获取帮助
- 官方文档: https://self-service-password.readthedocs.io/
- GitHub 项目: https://github.com/ltb-project/self-service-password
- 社区论坛: 相关技术论坛和社区
脚本问题反馈
如果您在使用脚本过程中遇到问题,请提供以下信息:
- 操作系统版本和架构
- 错误信息的完整输出
- 相关日志文件内容
- 使用的安装包版本
📄 许可证
本安装脚本基于实际部署经验编写,遵循开源精神,可自由使用和修改。
Self Service Password 本身遵循 GPL v3 许可证。
最后更新: 2025年6月
版本: v1.0
维护者: 大刘讲IT
#!/bin/bash
# =================================================================
# Self Service Password (SSP) One-Click Installation Script for Debian 12
#
# Author: Assistant (基于实际问题修复经验优化)
# Based on official documentation:
# - https://self-service-password.readthedocs.io/
# - https://github.com/ltb-project/self-service-password
#
# 版本: v3.7 - 完全移除自动 LDAP 配置,仅保留必要的安全设置
# =================================================================
# --- Script Configuration ---
# SSP 安装目录
INSTALL_DIR="/var/www/html/ssp"
# Apache 配置文件路径
APACHE_CONFIG_FILE="/etc/apache2/sites-available/ssp.conf"
# 脚本所在目录
SCRIPT_DIR="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
# --- 注意:不再自动修改 LDAP 配置 ---
# LDAP 配置请在安装完成后手动在 config.inc.php 中配置
# --- Command Line Arguments ---
FORCE_MODE=""
NON_INTERACTIVE=false
# 解析命令行参数
while [[ $# -gt 0 ]]; do
case $1 in
--force-fresh)
FORCE_MODE="fresh"
NON_INTERACTIVE=true
shift
;;
--force-upgrade)
FORCE_MODE="upgrade"
NON_INTERACTIVE=true
shift
;;
--force-reinstall)
FORCE_MODE="reinstall"
NON_INTERACTIVE=true
shift
;;
--non-interactive)
NON_INTERACTIVE=true
shift
;;
--install-dir)
INSTALL_DIR="$2"
shift 2
;;
--help|-h)
echo "Self Service Password 一键安装脚本"
echo ""
echo "用法: $0 [选项]"
echo ""
echo "选项:"
echo " --force-fresh 强制全新安装(忽略现有安装)"
echo " --force-upgrade 强制升级模式"
echo " --force-reinstall 强制重新安装"
echo " --non-interactive 非交互模式"
echo " --install-dir DIR 指定安装目录(默认: /var/www/html/ssp)"
echo " --help, -h 显示此帮助信息"
echo ""
echo "示例:"
echo " $0 # 交互式安装"
echo " $0 --force-fresh # 强制全新安装"
echo " $0 --force-upgrade # 强制升级现有安装"
echo " $0 --install-dir /opt/ssp # 安装到指定目录"
exit 0
;;
*)
echo "未知参数: $1"
echo "使用 --help 查看帮助信息"
exit 1
;;
esac
done
# 更新 Apache 配置文件路径(如果安装目录被修改)
if [ "$INSTALL_DIR" != "/var/www/html/ssp" ]; then
APACHE_CONFIG_FILE="/etc/apache2/sites-available/$(basename "$INSTALL_DIR").conf"
fi
# --- Color output functions ---
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}✅ $1${NC}"
}
print_error() {
echo -e "${RED}❌ $1${NC}"
}
print_warning() {
echo -e "${YELLOW}⚠️ $1${NC}"
}
print_info() {
echo -e "${BLUE}ℹ️ $1${NC}"
}
# --- Environment Check Function ---
function check_environment() {
echo "正在检查环境要求..."
# 检查操作系统
if ! grep -q "debian" /etc/os-release && ! grep -q "ubuntu" /etc/os-release; then
print_warning "此脚本专为 Debian/Ubuntu 系统设计"
fi
# 检查网络连接
if ! ping -c 1 114.114.114.114 >/dev/null 2>&1; then
print_warning "网络连接可能存在问题,某些功能可能受影响"
fi
print_success "环境检查完成"
}
# --- Installation Status Check Function ---
function check_installation_status() {
echo "正在检查现有安装状态..."
# 检查是否已经安装过
EXISTING_INSTALL=false
APACHE_INSTALLED=false
PHP_INSTALLED=false
SSP_INSTALLED=false
# 检查 Apache
if systemctl is-enabled apache2 >/dev/null 2>&1; then
APACHE_INSTALLED=true
print_info "检测到 Apache2 已安装"
fi
# 检查 PHP
if command -v php >/dev/null 2>&1; then
PHP_INSTALLED=true
PHP_VERSION=$(php -v | head -n1 | cut -d' ' -f2 | cut -d'.' -f1,2)
print_info "检测到 PHP 已安装 (版本: $PHP_VERSION)"
fi
# 检查 SSP 安装目录
if [ -d "$INSTALL_DIR" ]; then
SSP_INSTALLED=true
print_info "检测到 SSP 安装目录: $INSTALL_DIR"
if [ -f "$INSTALL_DIR/conf/config.inc.php" ]; then
print_info "检测到 SSP 配置文件存在"
fi
if [ -f "$APACHE_CONFIG_FILE" ]; then
print_info "检测到 Apache SSP 配置文件存在"
fi
EXISTING_INSTALL=true
fi
# 处理安装模式选择
if [ -n "$FORCE_MODE" ]; then
# 命令行指定了强制模式
INSTALL_MODE="$FORCE_MODE"
print_info "命令行强制模式: $INSTALL_MODE"
elif [ "$EXISTING_INSTALL" = true ]; then
# 检测到现有安装
if [ "$NON_INTERACTIVE" = true ]; then
# 非交互模式默认选择升级
INSTALL_MODE="upgrade"
print_info "非交互模式:自动选择升级模式"
else
# 交互模式询问用户
echo ""
print_warning "检测到现有的 SSP 安装!"
echo "您希望如何处理?"
echo " 1) 🔄 升级/重新配置现有安装"
echo " 2) 🗑️ 删除现有安装并重新安装"
echo " 3) 📂 保留现有安装并在新目录安装"
echo " 4) ❌ 退出安装"
echo ""
while true; do
read -p "请选择 (1-4): " choice
case $choice in
1)
INSTALL_MODE="upgrade"
print_info "选择:升级/重新配置模式"
break
;;
2)
INSTALL_MODE="reinstall"
print_info "选择:完全重新安装模式"
break
;;
3)
INSTALL_MODE="new_location"
print_info "选择:新位置安装模式"
read -p "请输入新的安装目录 [/var/www/html/ssp-new]: " new_dir
INSTALL_DIR=${new_dir:-/var/www/html/ssp-new}
# 更新 Apache 配置文件路径
APACHE_CONFIG_FILE="/etc/apache2/sites-available/$(basename "$INSTALL_DIR").conf"
break
;;
4)
print_info "用户选择退出安装"
exit 0
;;
*)
echo "无效选择,请重新输入"
;;
esac
done
fi
else
# 全新环境
INSTALL_MODE="fresh"
print_success "检测到全新环境,将进行首次安装"
fi
echo ""
}
# --- Cleanup Existing Installation ---
function cleanup_existing_installation() {
if [ "$INSTALL_MODE" = "reinstall" ]; then
echo "--> 清理现有安装..."
# 停止 Apache
print_info "停止 Apache 服务..."
systemctl stop apache2 2>/dev/null || true
# 禁用 SSP 站点
if [ -f "$APACHE_CONFIG_FILE" ]; then
print_info "禁用现有的 SSP 站点配置..."
a2dissite ssp.conf 2>/dev/null || true
fi
# 备份重要文件
if [ -d "$INSTALL_DIR" ]; then
BACKUP_DIR="/tmp/ssp_backup_$(date +%Y%m%d_%H%M%S)"
mkdir -p "$BACKUP_DIR"
# 备份配置文件
if [ -f "$INSTALL_DIR/conf/config.inc.php" ]; then
cp "$INSTALL_DIR/conf/config.inc.php" "$BACKUP_DIR/"
print_success "已备份配置文件到: $BACKUP_DIR/"
fi
# 备份自定义文件
if [ -d "$INSTALL_DIR/custom" ]; then
cp -r "$INSTALL_DIR/custom" "$BACKUP_DIR/"
print_success "已备份自定义文件"
fi
# 删除安装目录
rm -rf "$INSTALL_DIR"
print_success "已删除现有安装目录"
fi
# 删除 Apache 配置
if [ -f "$APACHE_CONFIG_FILE" ]; then
rm -f "$APACHE_CONFIG_FILE"
print_success "已删除 Apache 配置文件"
fi
print_success "现有安装清理完成,备份保存在: $BACKUP_DIR"
echo ""
fi
}
# --- Skip or Update Dependencies ---
function handle_dependencies() {
if [ "$APACHE_INSTALLED" = true ] && [ "$PHP_INSTALLED" = true ] && [ "$INSTALL_MODE" = "upgrade" ]; then
echo "--> 跳过依赖安装(检测到现有环境)..."
print_info "Apache 和 PHP 已安装,跳过系统依赖安装"
# 只更新必要的 PHP 模块
print_info "检查并安装缺失的 PHP 模块..."
apt-get update >/dev/null 2>&1
apt-get install -y --no-upgrade \
php8.2-ldap \
php8.2-ctype \
php8.2-mbstring \
php8.2-gd \
php8.2-xml \
php8.2-curl \
php8.2-zip \
php8.2-soap \
composer
print_success "PHP 模块检查完成"
return 0
else
return 1
fi
}
# --- Local Package Check Function ---
function find_ssp_package() {
echo "正在查找本地 SSP 安装包..."
# 可能的安装包文件名模式
local package_patterns=(
"self-service-password*.tar.gz"
"self-service-password*.zip"
"ssp*.tar.gz"
"ssp*.zip"
"*.tar.gz"
"*.zip"
)
SSP_PACKAGE=""
# 在脚本目录中查找安装包
for pattern in "${package_patterns[@]}"; do
for file in "${SCRIPT_DIR}"/$pattern; do
if [ -f "$file" ] && [ ! "$file" -ef "$0" ]; then
SSP_PACKAGE="$file"
print_success "找到 SSP 安装包: $(basename "$SSP_PACKAGE")"
return 0
fi
done
done
print_error "未在脚本目录中找到 SSP 安装包!"
echo "请将 Self Service Password 安装包放置在脚本同一目录中。"
echo "支持的文件格式: .tar.gz 或 .zip"
echo "推荐的文件名: self-service-password-*.tar.gz"
echo ""
echo "下载地址: https://github.com/ltb-project/self-service-password/releases"
exit 1
}
# --- Generate Secure Keyphrase --- (已移除,现在在 setup_config_file 中直接使用 openssl)
# --- Configuration File Setup ---
function setup_config_file() {
print_info "--> 步骤 7/10: 正在修改 SSP 配置文件(仅必要配置)..."
local CONFIG_FILE="${INSTALL_DIR}/conf/config.inc.php"
# 备份原始配置文件
cp "$CONFIG_FILE" "$CONFIG_FILE.backup.$(date +%Y%m%d_%H%M%S)"
# --- 生成必要的安全配置 ---
local SERVER_IP=$(hostname -I | awk '{print $1}')
local SECURE_KEYPHRASE=$(openssl rand -hex 32)
local RESET_URL="http://${SERVER_IP}/"
print_info "只修改必要的配置项..."
# 1. 设置安全的随机 keyphrase(这是必须的)
if grep -q "^\$keyphrase" "$CONFIG_FILE"; then
sed -i "s|^\$keyphrase = .*|\$keyphrase = \"${SECURE_KEYPHRASE}\";|" "$CONFIG_FILE"
print_success "已更新 keyphrase"
else
# 如果没有 keyphrase 行,添加它
echo "" >> "$CONFIG_FILE"
echo "# Security keyphrase (auto-generated)" >> "$CONFIG_FILE"
echo "\$keyphrase = \"${SECURE_KEYPHRASE}\";" >> "$CONFIG_FILE"
print_success "已添加 keyphrase"
fi
# 2. 设置 reset_url(基本功能需要)
if grep -q "^\$reset_url" "$CONFIG_FILE"; then
sed -i "s|^\$reset_url = .*|\$reset_url = \"${RESET_URL}\";|" "$CONFIG_FILE"
print_success "已更新 reset_url"
fi
# 3. 启用 debug 模式(便于排查问题)
if grep -q "^\$debug" "$CONFIG_FILE"; then
sed -i 's/^\$debug = .*/\$debug = true;/' "$CONFIG_FILE"
print_success "已启用 debug 模式"
fi
# 4. 添加 audit_log_file(防止未定义变量警告)
if ! grep -q "audit_log_file" "$CONFIG_FILE"; then
print_info "添加 audit_log_file 变量..."
echo "" >> "$CONFIG_FILE"
echo "# Audit log file" >> "$CONFIG_FILE"
echo "\$audit_log_file = \"${AUDIT_LOG}\";" >> "$CONFIG_FILE"
print_success "已添加 audit_log_file"
fi
# 5. 验证配置文件语法
print_info "验证配置文件语法..."
if php -l "$CONFIG_FILE" >/dev/null 2>&1; then
print_success "配置文件语法正确"
else
print_warning "配置文件存在语法错误,尝试修复..."
php -l "$CONFIG_FILE"
# 显示问题行附近的内容
ERROR_LINE=$(php -l "$CONFIG_FILE" 2>&1 | grep -o "line [0-9]*" | grep -o "[0-9]*")
if [ -n "$ERROR_LINE" ]; then
print_info "显示第${ERROR_LINE}行附近的内容:"
START_LINE=$((ERROR_LINE - 5))
END_LINE=$((ERROR_LINE + 5))
sed -n "${START_LINE},${END_LINE}p" "$CONFIG_FILE" | nl -ba -v${START_LINE}
# 针对性修复常见的 SMARTY 定义错误
if [ "$ERROR_LINE" -ge 505 ] && [ "$ERROR_LINE" -le 510 ]; then
print_info "检测到 SMARTY 定义相关错误,进行针对性修复..."
# 修复 define 语法错误
sed -i 's/if (!define("SMARTY"/if (!defined("SMARTY"))/g' "$CONFIG_FILE"
# 删除错误的行并重新写入正确的 SMARTY 定义
sed -i '/if (!defined("SMARTY"))/,/^[[:space:]]*}[[:space:]]*$/d' "$CONFIG_FILE"
# 在文件末尾添加正确的 SMARTY 定义
cat >> "$CONFIG_FILE" << SMARTY_EOF
# SMARTY template engine path (corrected)
if (!defined("SMARTY")) {
define("SMARTY", "${FOUND_SMARTY_PATH:-/var/www/html/ssp/vendor/smarty/smarty/libs/Smarty.class.php}");
}
SMARTY_EOF
# 验证修复结果
if php -l "$CONFIG_FILE" >/dev/null 2>&1; then
print_success "SMARTY 定义语法修复成功!"
else
print_warning "SMARTY 修复失败,使用紧急配置..."
fi
fi
fi
# 如果还是有错误,创建最小配置但不退出
if ! php -l "$CONFIG_FILE" >/dev/null 2>&1; then
print_warning "创建紧急最小配置文件(安装将继续)..."
cp "$CONFIG_FILE" "$CONFIG_FILE.broken"
cat > "$CONFIG_FILE" << EOF
<?php
#==============================================================================
# LTB Self Service Password - Emergency Minimal Configuration
#
# 注意:这是紧急生成的最小配置文件
# 损坏的原文件已保存为: $CONFIG_FILE.broken
# 请根据您的环境手动配置 LDAP 连接参数
#==============================================================================
# Debug mode
\$debug = true;
# Security (auto-generated)
\$keyphrase = "${SECURE_KEYPHRASE}";
\$reset_url = "${RESET_URL}";
# Audit log
\$audit_log_file = "${AUDIT_LOG}";
# SMARTY path (if found)
$([ -n "$FOUND_SMARTY_PATH" ] && echo "if (!defined(\"SMARTY\")) { define(\"SMARTY\", \"$FOUND_SMARTY_PATH\"); }")
?>
EOF
if php -l "$CONFIG_FILE" >/dev/null 2>&1; then
print_success "紧急最小配置文件创建成功!"
print_warning "⚠️ 这是最小配置,安装将继续完成,但您需要手动添加 LDAP 配置"
print_info "损坏的配置文件已保存为: $CONFIG_FILE.broken"
else
print_error "无法创建可用的配置文件,但安装将继续..."
print_warning "您需要在安装完成后手动修复配置文件"
fi
fi
fi
print_success "配置文件修改完成(仅修改了必要配置项)"
}
# --- 配置 Smarty 路径函数 ---
function configure_smarty_path() {
print_info "配置 Smarty 模板引擎路径..."
local CONFIG_FILE="${INSTALL_DIR}/conf/config.inc.php"
# 查找 vendor 目录中的 Smarty
SMARTY_CLASS_PATH=""
if [ -f "${INSTALL_DIR}/vendor/smarty/smarty/libs/Smarty.class.php" ]; then
SMARTY_CLASS_PATH="${INSTALL_DIR}/vendor/smarty/smarty/libs/Smarty.class.php"
elif [ -f "${INSTALL_DIR}/vendor/smarty/smarty/Smarty.class.php" ]; then
SMARTY_CLASS_PATH="${INSTALL_DIR}/vendor/smarty/smarty/Smarty.class.php"
else
# 搜索 vendor 目录中的 Smarty
SMARTY_CLASS_PATH=$(find "${INSTALL_DIR}/vendor" -name "Smarty.class.php" 2>/dev/null | head -1)
fi
# 如果找到了 Smarty,在配置文件中定义路径
if [ -n "$SMARTY_CLASS_PATH" ] && [ -f "$SMARTY_CLASS_PATH" ]; then
print_info "找到 Smarty: $SMARTY_CLASS_PATH"
# 检查是否已有 SMARTY 定义
if grep -q "define.*SMARTY" "$CONFIG_FILE"; then
sed -i "s|define.*SMARTY.*|define('SMARTY', '${SMARTY_CLASS_PATH}');|" "$CONFIG_FILE"
print_info "更新了现有的 SMARTY 定义"
else
# 在文件开头添加 SMARTY 定义(在 <?php 之后)
sed '/^<?php/a\
\
# Smarty template engine path\
define('\''SMARTY'\'', '\'''"${SMARTY_CLASS_PATH}"''\'');' "$CONFIG_FILE" > "$CONFIG_FILE.tmp"
mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
print_info "添加了新的 SMARTY 定义"
fi
print_success "Smarty 路径配置完成"
else
print_warning "未找到 Smarty,将依赖 autoload 自动加载"
fi
}
# --- Safety Checks ---
# 如果不以 root 身份运行,则退出
if [ "$(id -u)" -ne 0 ]; then
print_error "此脚本必须以 root 用户身份运行"
exit 1
fi
# 出现任何错误时立即中止脚本(但配置文件错误除外)
# set -e # 暂时禁用,改为手动错误检查以避免配置文件问题导致安装中断
# 确保包含 Apache 工具的路径
export PATH="/usr/sbin:/sbin:$PATH"
# --- Main Installation Process ---
echo "=================================================================="
echo "🚀 Self Service Password 一键安装脚本 v1.0"
echo "=================================================================="
echo "📋 大刘讲IT出品,微信公众号同号"
echo "=================================================================="
# 步骤 0: 环境检查
check_environment
# 步骤 0.1: 检查现有安装状态
check_installation_status
# 步骤 0.2: 处理现有安装
cleanup_existing_installation
# 步骤 0.5: 查找本地安装包
find_ssp_package
# 步骤 1: 更新系统并安装所有依赖项
echo "--> 1/9: 更新系统并安装依赖项..."
# 尝试智能跳过已安装的组件
if ! handle_dependencies; then
print_info "执行完整的依赖安装..."
apt-get update
if [ $? -ne 0 ]; then
print_error "系统更新失败"
exit 1
fi
# 设置为非交互模式,避免安装过程中断
export DEBIAN_FRONTEND=noninteractive
apt-get upgrade -y
if [ $? -ne 0 ]; then
print_warning "系统升级失败,但继续安装"
fi
apt-get install -y \
apache2 \
php8.2 \
php8.2-fpm \
libapache2-mod-php8.2 \
php8.2-ldap \
php8.2-ctype \
php8.2-iconv \
php8.2-gettext \
php8.2-mbstring \
php8.2-gd \
php8.2-xml \
php8.2-curl \
php8.2-zip \
php8.2-soap \
php8.2-cli \
composer \
wget \
tar \
unzip
if [ $? -ne 0 ]; then
print_error "依赖包安装失败"
exit 1
fi
print_success "依赖项安装完成"
else
print_success "依赖项检查完成(跳过重复安装)"
fi
echo ""
# 步骤 2: 配置 PHP 环境
echo "--> 2/9: 配置 PHP 环境..."
# 为 Apache 找到正确的 php.ini 文件
PHP_INI_FILE="/etc/php/8.2/apache2/php.ini"
if [ -f "$PHP_INI_FILE" ]; then
echo "在 ${PHP_INI_FILE} 中设置 PHP 配置..."
# 设置时区
if grep -q ";date.timezone =" "$PHP_INI_FILE"; then
sed -i 's/;date.timezone =/date.timezone = UTC/g' "$PHP_INI_FILE"
elif ! grep -q "^date.timezone" "$PHP_INI_FILE"; then
echo "date.timezone = UTC" >> "$PHP_INI_FILE"
fi
# 启用错误显示(调试用)
sed -i 's/display_errors = Off/display_errors = On/g' "$PHP_INI_FILE"
sed -i 's/display_startup_errors = Off/display_startup_errors = On/g' "$PHP_INI_FILE"
else
print_warning "未找到 Apache 的 php.ini 文件: ${PHP_INI_FILE}"
fi
print_success "PHP 配置完成"
echo ""
# 步骤 2.5: 配置 LDAP 客户端以临时禁用证书验证
echo "--> 2.5/10: 配置 LDAP 客户端以临时禁用证书验证..."
LDAP_CONF_FILE="/etc/ldap/ldap.conf"
# 检查是否已存在该配置,避免重复添加
if ! grep -q "^TLS_REQCERT" "$LDAP_CONF_FILE"; then
echo "" >> "$LDAP_CONF_FILE"
echo "# WARNING: This setting bypasses LDAPS certificate validation for initial setup." >> "$LDAP_CONF_FILE"
echo "# For production, you should import your CA cert and remove this line." >> "$LDAP_CONF_FILE"
echo "TLS_REQCERT never" >> "$LDAP_CONF_FILE"
print_success "已配置 LDAP 客户端以禁用证书验证。"
else
print_info "LDAP 客户端证书配置已存在,跳过。"
fi
echo ""
# 步骤 3: 解压并部署 Self Service Password
echo "--> 3/10: 解压并部署 Self Service Password..."
print_info "使用安装包: $(basename "$SSP_PACKAGE")"
# 创建安装目录
mkdir -p "${INSTALL_DIR}"
# 创建临时工作目录
TEMP_EXTRACT_DIR="/tmp/ssp_extract_$$"
mkdir -p "${TEMP_EXTRACT_DIR}"
# 根据文件扩展名解压
if [[ "$SSP_PACKAGE" == *.tar.gz ]] || [[ "$SSP_PACKAGE" == *.tgz ]]; then
echo "解压 tar.gz 格式文件..."
tar -xzf "${SSP_PACKAGE}" -C "${TEMP_EXTRACT_DIR}"
elif [[ "$SSP_PACKAGE" == *.zip ]]; then
echo "解压 zip 格式文件..."
unzip -q "${SSP_PACKAGE}" -d "${TEMP_EXTRACT_DIR}"
else
print_error "不支持的文件格式"
rm -rf "${TEMP_EXTRACT_DIR}"
exit 1
fi
if [ $? -ne 0 ]; then
print_error "解压失败"
rm -rf "${TEMP_EXTRACT_DIR}"
exit 1
fi
# 查找解压后的 SSP 目录
SSP_SOURCE_DIR=""
print_info "搜索解压后的 SSP 源码目录..."
# 首先检查解压目录的内容
print_info "解压目录内容:"
ls -la "${TEMP_EXTRACT_DIR}/"
# 智能查找 SSP 源码目录
for dir in "${TEMP_EXTRACT_DIR}"/*; do
if [ -d "$dir" ]; then
print_info "检查目录: $(basename "$dir")"
if [ -f "$dir/composer.json" ] || [ -d "$dir/htdocs" ] || [ -f "$dir/index.php" ]; then
SSP_SOURCE_DIR="$dir"
print_success "找到有效的 SSP 源码目录: $(basename "$SSP_SOURCE_DIR")"
break
fi
fi
done
# 如果在子目录中没找到,检查解压根目录
if [ -z "$SSP_SOURCE_DIR" ]; then
print_info "在子目录中未找到,检查解压根目录..."
if [ -f "${TEMP_EXTRACT_DIR}/composer.json" ] || [ -d "${TEMP_EXTRACT_DIR}/htdocs" ] || [ -f "${TEMP_EXTRACT_DIR}/index.php" ]; then
SSP_SOURCE_DIR="${TEMP_EXTRACT_DIR}"
print_success "在解压根目录找到 SSP 源码"
fi
fi
# 如果还是没找到,列出所有可能的文件
if [ -z "$SSP_SOURCE_DIR" ]; then
print_error "无法找到有效的 SSP 源代码目录"
print_info "解压目录完整内容:"
find "${TEMP_EXTRACT_DIR}" -type f -name "*.php" -o -name "composer.json" -o -name "*.md" | head -20
rm -rf "${TEMP_EXTRACT_DIR}"
exit 1
fi
# 复制文件到安装目录
print_info "复制文件从 $(basename "$SSP_SOURCE_DIR") 到 ${INSTALL_DIR}..."
cp -r "${SSP_SOURCE_DIR}"/* "${INSTALL_DIR}/"
if [ $? -ne 0 ]; then
print_error "复制文件失败"
rm -rf "${TEMP_EXTRACT_DIR}"
exit 1
fi
# 验证关键文件是否存在
print_info "验证关键文件..."
if [ -f "${INSTALL_DIR}/composer.json" ]; then
print_success "composer.json 文件存在"
else
print_warning "composer.json 文件不存在"
fi
if [ -d "${INSTALL_DIR}/htdocs" ]; then
print_success "htdocs 目录存在"
else
print_warning "htdocs 目录不存在"
fi
# 清理临时文件
rm -rf "${TEMP_EXTRACT_DIR}"
print_success "SSP 已解压到 ${INSTALL_DIR}"
echo ""
# 步骤 4: 强制全新安装 PHP 依赖
echo "--> 4/9: 强制全新安装 PHP 依赖..."
cd "${INSTALL_DIR}"
print_info "清理旧的依赖状态以确保全新安装..."
rm -rf vendor composer.lock
# 设置 Composer 环境变量
export COMPOSER_ALLOW_SUPERUSER=1
export COMPOSER_HOME="/tmp/composer"
export COMPOSER_CACHE_DIR="/tmp/composer/cache"
# 强制检查和安装 Composer 依赖
print_info "检查 Composer 依赖安装状态..."
if [ -f "composer.json" ]; then
print_success "找到 composer.json 文件"
# 显示 composer.json 内容以便调试
print_info "composer.json 内容预览:"
head -10 composer.json
print_info "强制全新安装 Composer 依赖..."
# 设置 Composer 环境变量
export COMPOSER_ALLOW_SUPERUSER=1
export COMPOSER_HOME="/tmp/composer"
export COMPOSER_CACHE_DIR="/tmp/composer/cache"
# 强制删除现有的 vendor 目录和锁文件
rm -rf vendor composer.lock
# 安装依赖
print_info "正在运行 composer install..."
composer install --no-dev --optimize-autoloader --verbose
if [ $? -ne 0 ]; then
print_error "Composer install 失败,尝试更新 Composer 并重试..."
composer self-update
composer install --no-dev --optimize-autoloader --verbose
if [ $? -ne 0 ]; then
print_error "Composer 安装仍然失败"
exit 1
fi
fi
# 验证关键依赖
print_info "验证关键依赖是否安装成功..."
if [ ! -f "vendor/autoload.php" ]; then
print_error "vendor/autoload.php 文件不存在!"
exit 1
else
print_success "vendor/autoload.php 文件存在"
fi
# 检查并安装缺失的关键依赖
if [ ! -d "vendor/defuse/php-encryption" ]; then
print_warning "检测到核心加密库缺失,正在强制安装..."
composer require defuse/php-encryption:"^2.2"
else
print_success "Defuse 加密库已安装"
fi
# 检查 LTB 项目依赖
if [ ! -d "vendor/ltb-project" ]; then
print_warning "检测到 LTB 项目库缺失,正在尝试安装..."
composer require ltb-project/ldap:"^0.3" || print_warning "LTB LDAP 库安装失败,将依赖内置类"
else
print_success "LTB 项目库已安装"
fi
print_info "设置 vendor 目录权限..."
chown -R www-data:www-data vendor composer.lock
print_success "Composer 依赖安装并验证完成"
else
print_error "未找到 composer.json 文件!"
print_info "当前目录内容:"
ls -la
print_info "搜索可能的 composer.json 文件..."
find . -name "composer.json" -type f 2>/dev/null || print_warning "确实没有找到 composer.json 文件"
# 尝试创建一个基本的 composer.json
print_warning "尝试创建基本的 composer.json 文件..."
cat > composer.json << 'EOF'
{
"name": "ltb-project/self-service-password",
"description": "Self Service Password",
"type": "project",
"require": {
"php": ">=7.4",
"defuse/php-encryption": "^2.2",
"ltb-project/ldap": "^0.3",
"smarty/smarty": "^3.1"
},
"autoload": {
"psr-4": {
"Ltb\\": "src/Ltb/"
}
}
}
EOF
print_info "创建了基本的 composer.json,重新尝试安装..."
# 创建基本的 src/Ltb 目录结构
mkdir -p src/Ltb
# 重新运行 Composer 安装
export COMPOSER_ALLOW_SUPERUSER=1
composer install --no-dev --optimize-autoloader
if [ $? -ne 0 ]; then
print_error "即使创建了 composer.json 也无法安装依赖"
exit 1
fi
print_success "使用创建的 composer.json 成功安装依赖"
fi
# 最终验证
print_info "最终验证 autoload.php..."
if [ -f "vendor/autoload.php" ]; then
print_success "✅ vendor/autoload.php 文件确认存在"
else
print_error "❌ vendor/autoload.php 文件仍然不存在!"
exit 1
fi
# 检查并修复 Smarty 路径配置
print_info "检查和修复 Smarty 路径配置..."
SMARTY_PATHS=(
"${INSTALL_DIR}/vendor/smarty/smarty/libs/Smarty.class.php"
"${INSTALL_DIR}/vendor/smarty/smarty/Smarty.class.php"
"${INSTALL_DIR}/vendor/smarty/smarty/src/Smarty.php"
)
FOUND_SMARTY_PATH=""
for path in "${SMARTY_PATHS[@]}"; do
if [ -f "$path" ]; then
FOUND_SMARTY_PATH="$path"
print_success "找到 Smarty: $path"
break
fi
done
if [ -n "$FOUND_SMARTY_PATH" ]; then
CONFIG_FILE="${INSTALL_DIR}/conf/config.inc.php"
if [ -f "$CONFIG_FILE" ]; then
print_info "更新配置文件中的 Smarty 路径..."
# 检查是否已有 SMARTY 定义
if grep -q "define.*SMARTY" "$CONFIG_FILE"; then
print_info "更新现有的 SMARTY 定义..."
sed -i "s|define.*SMARTY.*|define(\"SMARTY\", \"$FOUND_SMARTY_PATH\");|" "$CONFIG_FILE"
else
print_info "添加新的 SMARTY 定义..."
# 在 <?php 后添加 SMARTY 定义(使用更安全的方法)
sed '/^<?php/a\
\
# Smarty template engine path (auto-detected)\
define("SMARTY", "'"$FOUND_SMARTY_PATH"'");' "$CONFIG_FILE" > "$CONFIG_FILE.tmp"
mv "$CONFIG_FILE.tmp" "$CONFIG_FILE"
fi
print_success "Smarty 路径已更新到配置文件"
# 验证配置文件语法
if php -l "$CONFIG_FILE" >/dev/null 2>&1; then
print_success "配置文件语法验证通过"
else
print_warning "配置文件语法验证失败,但 Smarty 路径已更新"
fi
else
print_warning "配置文件不存在,跳过 Smarty 路径更新"
fi
else
print_warning "未找到 Smarty 文件,将依赖 autoload 自动加载"
fi
# 检查其他关键依赖路径
print_info "检查其他关键依赖..."
# 检查 Defuse 加密库
if [ -d "${INSTALL_DIR}/vendor/defuse/php-encryption" ]; then
print_success "Defuse 加密库已安装"
else
print_warning "Defuse 加密库未找到"
fi
# 检查 LTB 项目依赖
if [ -d "${INSTALL_DIR}/vendor/ltb-project" ]; then
print_success "LTB 项目依赖已安装"
else
print_warning "LTB 项目依赖未找到"
fi
# 检查关键目录权限
CRITICAL_DIRS=(
"${INSTALL_DIR}/conf"
"${INSTALL_DIR}/cache"
"${INSTALL_DIR}/compile"
"${INSTALL_DIR}/templates_c"
"${INSTALL_DIR}/vendor"
)
print_info "验证关键目录权限..."
for dir in "${CRITICAL_DIRS[@]}"; do
if [ -d "$dir" ]; then
if [ -w "$dir" ]; then
print_success "目录 $(basename "$dir") 权限正确"
else
print_warning "目录 $(basename "$dir") 权限可能有问题"
chown -R www-data:www-data "$dir"
chmod -R 750 "$dir"
print_info "已修复目录 $(basename "$dir") 权限"
fi
else
print_warning "目录 $(basename "$dir") 不存在"
fi
done
echo ""
# 步骤 6: 跳过手动创建 Ltb 类(使用 Composer 官方依赖)
echo "--> 6/10: 跳过手动创建 Ltb 类,使用 Composer 官方依赖..."
print_success "已跳过手动创建 Ltb 类,将依赖 Composer 安装的官方包"
echo ""
# 步骤 5: 设置配置文件
echo "--> 5/9: 设置配置文件..."
setup_config_file
echo ""
# 步骤 6: 跳过单独的 Smarty 配置(已集成到 Composer 步骤)
echo "--> 6/9: Smarty 路径配置已集成到 Composer 安装步骤..."
print_success "Smarty 路径配置已在 Composer 安装后自动完成"
echo ""
# 步骤 7: 设置文件和目录权限
echo "--> 7/9: 设置文件权限..."
# 创建必要的目录
print_info "创建必要的目录..."
mkdir -p "${INSTALL_DIR}/cache" "${INSTALL_DIR}/compile" "${INSTALL_DIR}/templates_c"
# PHP sessions 由系统管理
if [ -d "/var/lib/php/sessions" ]; then
print_info "配置系统 PHP sessions 目录权限..."
chown root:www-data /var/lib/php/sessions
chmod 770 /var/lib/php/sessions
fi
# 创建审计日志文件
AUDIT_LOG="/var/log/apache2/ssp_audit.log"
touch "$AUDIT_LOG"
chown www-data:www-data "$AUDIT_LOG"
chmod 644 "$AUDIT_LOG"
print_success "创建审计日志文件: $AUDIT_LOG"
# 设置基本目录权限
print_info "设置目录权限..."
chown -R www-data:www-data "${INSTALL_DIR}"
chmod -R 755 "${INSTALL_DIR}"
# 设置特殊权限的目录
directories_to_set=(
"${INSTALL_DIR}/conf"
"${INSTALL_DIR}/cache"
"${INSTALL_DIR}/compile"
"${INSTALL_DIR}/templates_c"
)
for dir in "${directories_to_set[@]}"; do
if [ -d "$dir" ]; then
print_info "设置 $(basename "$dir") 目录权限..."
chown -R www-data:www-data "$dir"
chmod -R 750 "$dir"
fi
done
print_success "文件权限设置完成"
echo ""
# 步骤 8: 配置 Apache Web 服务器
echo "--> 8/9: 配置 Apache2..."
# 根据官方文档创建 Apache 虚拟主机配置文件
# 参考: https://self-service-password.readthedocs.io/en/latest/config_apache.html
cat > "${APACHE_CONFIG_FILE}" << EOF
<VirtualHost *:80>
ServerName localhost
DocumentRoot ${INSTALL_DIR}/htdocs
DirectoryIndex index.php
# 设置默认字符集
AddDefaultCharset UTF-8
<Directory ${INSTALL_DIR}/htdocs>
# 根据官方文档,设置 AllowOverride None
AllowOverride None
<IfVersion >= 2.3>
Require all granted
</IfVersion>
<IfVersion < 2.3>
Order Deny,Allow
Allow from all
</IfVersion>
# 确保 index.php 作为目录索引
DirectoryIndex index.php
AddDefaultCharset UTF-8
</Directory>
# 保护配置目录
<Directory ${INSTALL_DIR}/conf>
<IfVersion >= 2.3>
Require all denied
</IfVersion>
<IfVersion < 2.3>
Order Deny,Allow
Deny from all
</IfVersion>
</Directory>
# 保护缓存目录
<Directory ${INSTALL_DIR}/cache>
<IfVersion >= 2.3>
Require all denied
</IfVersion>
<IfVersion < 2.3>
Order Deny,Allow
Deny from all
</IfVersion>
</Directory>
# 保护编译目录
<Directory ${INSTALL_DIR}/compile>
<IfVersion >= 2.3>
Require all denied
</IfVersion>
<IfVersion < 2.3>
Order Deny,Allow
Deny from all
</IfVersion>
</Directory>
# 保护模板编译目录
<Directory ${INSTALL_DIR}/templates_c>
<IfVersion >= 2.3>
Require all denied
</IfVersion>
<IfVersion < 2.3>
Order Deny,Allow
Deny from all
</IfVersion>
</Directory>
# 如果存在 rest API 目录,保护它
<Directory ${INSTALL_DIR}/rest>
AllowOverride None
<IfVersion >= 2.3>
Require all denied
</IfVersion>
<IfVersion < 2.3>
Order Deny,Allow
Deny from all
</IfVersion>
</Directory>
# 日志配置
LogLevel warn
ErrorLog \${APACHE_LOG_DIR}/ssp_error.log
CustomLog \${APACHE_LOG_DIR}/ssp_access.log combined
</VirtualHost>
EOF
# 启用 Apache 模块和站点配置
print_info "启用 Apache 模块和站点配置..."
# 检查并启用必要的 Apache 模块
check_module() {
local module=$1
if apache2ctl -M 2>/dev/null | grep -q "${module}_module"; then
print_info "模块 $module 已启用"
return 0
else
print_info "启用模块 $module..."
/usr/sbin/a2enmod $module
return $?
fi
}
# 启用必要的模块
check_module "rewrite"
check_module "php8.2"
check_module "dir"
# 禁用可能冲突的站点
print_info "禁用默认站点..."
/usr/sbin/a2dissite 000-default.conf 2>/dev/null || true
# 启用 SSP 站点
print_info "启用 SSP 站点..."
/usr/sbin/a2ensite ssp.conf
# 检查 .htaccess 文件(由于使用 AllowOverride None,需要禁用)
HTACCESS_FILE="${INSTALL_DIR}/htdocs/.htaccess"
if [ -f "$HTACCESS_FILE" ]; then
print_info "发现 .htaccess 文件,由于使用 AllowOverride None,将其重命名"
mv "$HTACCESS_FILE" "${HTACCESS_FILE}.disabled"
print_warning "已将 .htaccess 重命名为 .htaccess.disabled"
fi
# 测试 Apache 配置
if ! apache2ctl configtest; then
print_error "Apache 配置测试失败"
exit 1
fi
# 检查并启动 Apache 服务
print_info "检查 Apache 服务状态..."
if ! systemctl is-active --quiet apache2; then
print_warning "Apache 服务未运行,正在启动..."
systemctl start apache2
if [ $? -ne 0 ]; then
print_error "Apache 启动失败,尝试重新安装并启动..."
systemctl enable apache2
systemctl start apache2
if [ $? -ne 0 ]; then
print_error "Apache 启动失败"
systemctl status apache2
exit 1
fi
fi
print_success "Apache 服务启动成功"
else
print_info "Apache 服务已在运行"
fi
# 重新加载 Apache 配置
print_info "重新加载 Apache 配置..."
systemctl reload apache2
if [ $? -ne 0 ]; then
print_warning "Apache 配置重新加载失败,尝试重启..."
systemctl restart apache2
if [ $? -ne 0 ]; then
print_error "Apache 重启失败"
systemctl status apache2
exit 1
else
print_success "Apache 重启成功"
fi
else
print_success "Apache 配置重新加载成功"
fi
# 验证 Apache 状态
if ! systemctl is-active --quiet apache2; then
print_error "Apache 服务未正常运行"
exit 1
fi
print_success "Apache 配置完成"
echo ""
# --- 创建简化的安装验证页面 ---
echo "--> 创建一个简化的安装验证页面..."
cat > "${INSTALL_DIR}/htdocs/install_check.php" << 'EOF'
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
echo "<html><head><title>SSP 核心依赖检查</title>";
echo "<style>body{font-family:monospace;margin:40px;} .ok{color:green;} .err{color:red;}</style>";
echo "</head><body><h1>SSP Core Dependency Check</h1>";
$all_ok = true;
// 1. 检查 Composer Autoloader
echo "<h2>1. Composer Autoloader</h2>";
$autoload_file = __DIR__ . '/../vendor/autoload.php';
if (file_exists($autoload_file)) {
require_once $autoload_file;
echo "<p class='ok'>[OK] vendor/autoload.php found and included.</p>";
} else {
echo "<p class='err'>[FAIL] vendor/autoload.php not found!</p>";
$all_ok = false;
}
// 2. 检查核心 LTB 类
echo "<h2>2. LTB Project Core Class</h2>";
if (class_exists('Ltb\Directory')) {
echo "<p class='ok'>[OK] Ltb\\Directory class is available.</p>";
} else {
echo "<p class='err'>[FAIL] Ltb\\Directory class not found!</p>";
$all_ok = false;
}
// 3. 检查核心加密库
echo "<h2>3. Defuse Crypto Library</h2>";
if (class_exists('Defuse\\Crypto\\Crypto')) {
echo "<p class='ok'>[OK] Defuse\\Crypto\\Crypto class is available.</p>";
} else {
echo "<p class='err'>[FAIL] Defuse\\Crypto\\Crypto class not found!</p>";
$all_ok = false;
}
echo "<h2>Final Result</h2>";
if ($all_ok) {
echo "<h3 class='ok'>ALL CHECKS PASSED! Your SSP installation should be working correctly.</h3>";
echo "<p><a href='./'>→ Go to SSP Main Page</a></p>";
} else {
echo "<h3 class='err'>SOME CHECKS FAILED! Please review the errors above.</h3>";
}
echo "</body></html>";
?>
EOF
chown www-data:www-data "${INSTALL_DIR}/htdocs/install_check.php"
chmod 644 "${INSTALL_DIR}/htdocs/install_check.php"
# --- 步骤 9: 最终验证 ---
echo ""
echo "--> 9/9: 最终验证安装..."
# 验证配置文件语法
print_info "验证配置文件语法..."
php -l "${INSTALL_DIR}/conf/config.inc.php"
if [ $? -eq 0 ]; then
print_success "配置文件语法正确"
else
print_error "配置文件语法错误"
fi
# 验证 Apache 状态
if systemctl is-active --quiet apache2; then
print_success "Apache 服务运行正常"
else
print_error "Apache 服务未运行"
fi
print_success "最终验证完成"
# --- 获取服务器信息 ---
SERVER_IP=$(hostname -I | awk '{print $1}')
# --- Final Instructions ---
echo ""
echo "=================================================================="
case "$INSTALL_MODE" in
"fresh")
print_success "🎉 Self Service Password 全新安装完成!"
;;
"upgrade")
print_success "🔄 Self Service Password 升级完成!"
;;
"reinstall")
print_success "🔄 Self Service Password 重新安装完成!"
if [ -n "$BACKUP_DIR" ]; then
echo " 💾 原配置备份: $BACKUP_DIR"
fi
;;
"new_location")
print_success "📂 Self Service Password 新位置安装完成!"
;;
*)
print_success "🎉 Self Service Password 安装完成!"
;;
esac
echo "=================================================================="
echo ""
echo "🔗 **访问地址**:"
echo " 📋 核心依赖检查: http://${SERVER_IP}/install_check.php"
echo " 🏠 SSP 主页: http://${SERVER_IP}/"
echo " 🌐 本机访问: http://localhost/"
echo ""
echo "📋 **安装信息**:"
echo " 🏗️ 安装模式: $INSTALL_MODE"
echo " 📦 安装包: $(basename "$SSP_PACKAGE")"
echo " 📁 安装目录: ${INSTALL_DIR}"
echo " ⚙️ Apache 配置: ${APACHE_CONFIG_FILE}"
echo " 🌐 服务器 IP: ${SERVER_IP}"
echo " 📝 审计日志: ${AUDIT_LOG}"
echo ""
echo "📝 **Apache 配置优化**:"
echo " ✅ 根据官方文档配置 Apache"
echo " ✅ 设置 AllowOverride None(官方推荐)"
echo " ✅ 添加正确的目录保护"
echo " ✅ 设置默认字符集 UTF-8"
echo " ✅ 禁用可能冲突的 .htaccess"
echo ""
echo "🔧 **依赖管理优化**:"
echo " ✅ 强制清理旧的 vendor 目录和 composer.lock"
echo " ✅ 简化 Composer 执行逻辑(root 安装 + 权限修正)"
echo " ✅ 自动检测并安装缺失的核心加密库"
echo " ✅ 依赖官方 Composer 包,避免手动创建不完整类"
echo ""
echo "🔧 **配置文件优化修复**:"
echo " ✅ 仅修改必要的配置项(keyphrase、reset_url、debug)"
echo " ✅ 自动添加 audit_log_file 变量(防止未定义警告)"
echo " ✅ 智能配置 Smarty 模板引擎路径"
echo " ✅ 生成安全的随机密钥短语"
echo " ✅ 智能语法错误检测和修复"
echo " ✅ 紧急配置文件重建功能"
echo ""
echo "🔧 **下一步操作**:"
echo " 1. 访问核心依赖检查页面确认安装状态"
echo " 2. 手动配置 LDAP/AD 连接(编辑 ${INSTALL_DIR}/conf/config.inc.php)"
echo " 3. 访问 SSP 主页开始使用"
echo ""
echo "📚 **故障排除**:"
echo " 🔍 查看 Apache 错误日志: tail -f /var/log/apache2/ssp_error.log"
echo " 🔍 查看 Apache 访问日志: tail -f /var/log/apache2/ssp_access.log"
echo " 🧪 测试 Apache 配置: apache2ctl configtest"
echo " 🔄 重启 Apache: systemctl restart apache2"
echo " 🔧 修复配置文件语法: ./fix_config_syntax.sh"
echo " 📝 检查配置文件语法: php -l ${INSTALL_DIR}/conf/config.inc.php"
echo ""
print_success "安装脚本执行完毕!享受您的 Self Service Password!"

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)