这里的一件安装脚本的前提,是将对应的文件放在对应的目录后,然后给脚本增加权限 chmod +x xxx.sh然后在打开脚本修改里面必须修改点,最后执行脚本,即可一件安装完成,
比如: 达梦数据库 DM8
-
将压缩包放在 /dm8 目录下面(目录如果不存在 则创建或者缓存别的目录也可以-对应脚本里面的
UNZIP_DIR目录) -
将dm.key 放在
DM_KEY_FILE对应的目录下面 -
修改脚本里面的
INSTALL_DIR数据库存储目录 -
配置数据库名称和实列名称
DB_NAME="DM_DB1" # 数据库名
INSTANCE_NAME="DM_DB1" # 实例名 -
配置数据库各种密码
sh
SYSDBA_PWD="DM_DB1SYSDBAr" # SYSDBA密码
SYSSSO_PWD="DM_DB1SYSDBA" # SYSSSO密码
SYSAUDITOR_PWD="DM_DB1SAUDITOR" # SYSAUDITOR密码
DM_USER_PWD="DM_DB1_USER_PWD" # dm操作系统用户密码(可自定义)
6.给脚本增加权限 chmod +x xxx.sh
- root用户执行 ./xxx.sh 即可完成安装,最后在试一下远程链接即可
达梦数据库 DM8
sh
#!/bin/bash
##############################################################################
# 达梦数据库 DM8 单机模式自动安装脚本(修复点标记版)
# 核心修复:解决"非root用户不自动创建系统服务"问题
# 适用系统:RedHat/CentOS 7.x (x86_64) / 麒麟V10
##############################################################################
# ==================== 基础配置(所有参数可动态调整)====================
# 1. 路径配置(动态注入XML)
UNZIP_DIR="/dm8" # 解压目录(自动创建)
ZIP_PACKAGE="dm8_20250506_x86_rh7_64.zip" # 达梦压缩包名称(需与上传文件一致)
ISO_FILE="dm8_20250506_x86_rh7_64.iso" # 解压后ISO文件名(压缩包内默认名称)
MOUNT_DIR="/mnt" # 临时挂载目录(安装后卸载)
INSTALL_DIR="/data/dm" # 数据库安装目录(纯安装文件,文档推荐)
DATA_DIR="${INSTALL_DIR}/dmdata" # 数据文件目录(安装后创建)
DM_USER="dm" # 文档规范:数据库专用用户(dmdba)
DM_GROUP="dinstall" # 官方强制用户组(文档一致)
DM_KEY_FILE="/opt/dm.key" # 授权文件路径(dm.key,无则设为DM_KEY_FILE="")
DB_NAME="DM_DB1" # 数据库名
INSTANCE_NAME="DM_DB1" # 实例名
PORT_NUM="5236" # 数据库端口
ARCHIVE_DIR="${INSTALL_DIR}/dmarch" # 归档目录(安装后创建)
BACKUP_DIR="${INSTALL_DIR}/dmbak" # 备份目录(安装后创建)
# 2. XML专用动态配置(严格遵循官方规范)
CASE_SENSITIVE="N" # 大小写敏感(对应XML:CASE_SENSITIVE)
CHARSET="1" # 字符集(0=GB18030,1=UTF-8,对应XML:CHARSET)
EXTENT_SIZE="32" # 扩展页大小(对应XML:EXTENT_SIZE)
PAGE_SIZE="32" # 页大小(对应XML:PAGE_SIZE)
LOG_SIZE="4096" # 日志大小(对应XML:LOG_SIZE)
INIT_DB="Y" # 自动初始化数据库(对应XML:INIT_DB)
ENCRYPT_NAME="AES256_ECB" # 加密算法(对应XML:ENCRYPT_NAME)
USE_NEW_HASH="1" # 新哈希算法(对应XML:USE_NEW_HASH)
# 3. 密码配置(动态注入XML,符合复杂度要求)
SYSDBA_PWD="DM_DB1SYSDBAr" # SYSDBA密码
SYSSSO_PWD="DM_DB1SYSDBA" # SYSSSO密码
SYSAUDITOR_PWD="DM_DB1SAUDITOR" # SYSAUDITOR密码
DM_USER_PWD="DM_DB1_USER_PWD" # dm操作系统用户密码(可自定义)
# 4. 单机配置(无需主从相关配置)
CURRENT_INSTANCE_NAME="${INSTANCE_NAME}" # 当前实例名
LOCAL_IP="" # 本机IP
# 【修复点2】新增变量存储dm.ini路径,避免重复计算,方便服务创建
DM_INI_PATH=""
# ==================== 工具函数(增强稳定性)====================
log_info() {
echo -e "\033[32m[INFO] $(date +'%Y-%m-%d %H:%M:%S'): $1\033[0m"
}
log_error() {
echo -e "\033[31m[ERROR] $(date +'%Y-%m-%d %H:%M:%S'): $1\033[0m"
exit 1
}
log_warn() {
echo -e "\033[33m[WARN] $(date +'%Y-%m-%d %H:%M:%S'): $1\033[0m"
}
# 自动获取本机有效IP
get_local_ip() {
local local_ip=$(ip addr | grep -E 'inet (192\.168\.|10\.|172\.(1[6-9]|2[0-9]|3[0-1]))' | grep -v 'docker' | grep -v 'lo' | awk '{print $2}' | cut -d '/' -f 1 | head -n 1)
if [ -z "${local_ip}" ]; then
local_ip=$(ip addr | grep 'inet ' | grep -v '127.0.0.1' | grep -v 'docker' | awk '{print $2}' | cut -d '/' -f 1 | head -n 1)
fi
if [ -z "${local_ip}" ]; then
log_warn "无法自动获取本机IP,请手动输入"
read -p "请输入当前服务器IP:" local_ip
if ! validate_ip "${local_ip}"; then
log_error "IP格式非法(示例:192.168.1.100)"
fi
fi
echo "${local_ip}"
}
# 端口占用检查
check_port() {
local port=$1
if command -v ss &> /dev/null; then
ss -tulpn | grep -q ":${port} " && log_error "端口${port}已占用,请更换"
else
netstat -tulpn | grep -q ":${port} " && log_error "端口${port}已占用,请更换"
fi
}
# IP格式校验
validate_ip() {
local ip=$1
if ! echo "${ip}" | grep -E '^([0-9]{1,3}\.){3}[0-9]{1,3}$'; then
return 1
fi
local IFS='.'
read -r a b c d <<< "${ip}"
[ $a -ge 0 ] && [ $a -le 255 ] && [ $b -ge 0 ] && [ $b -le 255 ] && [ $c -ge 0 ] && [ $c -le 255 ] && [ $d -ge 0 ] && [ $d -le 255 ]
}
# 目录权限校验
check_dir_perm() {
local dir=$1
local expected_owner="${DM_USER}:${DM_GROUP}"
local expected_perm=$2
local actual_owner=$(stat -c "%U:%G" "${dir}")
[ "${actual_owner}" != "${expected_owner}" ] && log_error "目录${dir}所有者错误,需为${expected_owner}"
local actual_perm=$(stat -c "%a" "${dir}")
if [ "${actual_perm}" -ne "${expected_perm}" ]; then
log_warn "目录${dir}权限修正(期望${expected_perm},实际${actual_perm})"
chmod ${expected_perm} "${dir}"
fi
}
# 核心修复函数:root用户手动创建系统服务(解决dmdba无权限问题)
# 逻辑:调用达梦官方服务安装脚本,root权限执行,确保服务创建成功
create_system_service() {
log_info "==================== 【核心修复】root用户创建系统服务 ====================="
# 1. 校验实例配置文件是否存在(服务创建必需)
DM_INI_PATH="${DATA_DIR}/${DB_NAME}/dm.ini"
if [ ! -f "${DM_INI_PATH}" ]; then
log_error "实例配置文件${DM_INI_PATH}不存在!无法创建服务"
fi
# 2. 校验达梦官方服务安装脚本(确保脚本存在)
local service_script="${INSTALL_DIR}/script/root/dm_service_installer.sh"
if [ ! -f "${service_script}" ]; then
log_error "未找到官方服务安装脚本:${service_script}(安装失败)"
fi
# 3. 检查服务是否已存在(避免重复创建)
local service_name="DmService${CURRENT_INSTANCE_NAME}"
if systemctl list-unit-files | grep -q "${service_name}"; then
log_info "系统服务${service_name}已存在,跳过创建"
# 确保服务是启动状态
systemctl start "${service_name}" >/dev/null 2>&1
systemctl enable "${service_name}" >/dev/null 2>&1
log_info "✅ 服务${service_name}已启动并设置开机自启"
return
fi
# 4. 【关键命令】root执行官方脚本创建服务(核心修复逻辑)
log_info "执行官方脚本创建服务:${service_script}"
${service_script} -t dmserver -p "${CURRENT_INSTANCE_NAME}" -dm_ini "${DM_INI_PATH}" || {
log_error "服务创建失败!请手动执行:${service_script} -t dmserver -p ${CURRENT_INSTANCE_NAME} -dm_ini ${DM_INI_PATH}"
}
# 5. 验证服务创建结果
if ! systemctl list-unit-files | grep -q "${service_name}"; then
log_error "服务${service_name}创建失败!请检查dm.ini路径和权限"
fi
# 6. 设置开机自启并启动服务(满足原需求)
systemctl enable "${service_name}" >/dev/null 2>&1 || log_warn "服务开机自启设置失败,需手动执行:systemctl enable ${service_name}"
systemctl start "${service_name}" >/dev/null 2>&1 || {
log_error "服务${service_name}启动失败!请手动执行:systemctl start ${service_name}"
}
# 7. 验证服务状态(确保修复生效)
sleep 5
if systemctl is-active --quiet "${service_name}"; then
log_info "✅ 【修复成功】系统服务${service_name}创建并启动正常(root权限生效)"
else
log_error "服务${service_name}创建成功但启动失败!状态:$(systemctl status "${service_name}" | grep Active)"
fi
}
# ==================== 交互式配置(单机模式简化)====================
interactive_input() {
log_info "==================== 单机模式配置 ===================="
# 自动获取本机IP
LOCAL_IP=$(get_local_ip)
log_info "自动获取本机IP:${LOCAL_IP},实例名:${CURRENT_INSTANCE_NAME}"
# 配置汇总(标注服务创建方式)
local charset_desc="GB18030"
if [ "${CHARSET}" = "1" ]; then
charset_desc="UTF-8"
fi
echo -e "\n=========================================================="
echo "当前配置汇总(【修复说明】服务将由root用户手动创建):"
echo " 模式:单机 | 本机IP:${LOCAL_IP}"
echo " 实例名:${CURRENT_INSTANCE_NAME} | 端口:${PORT_NUM}"
echo " 安装目录:${INSTALL_DIR} | 数据目录:${DATA_DIR}(安装后创建)"
echo " 服务名:DmService${CURRENT_INSTANCE_NAME}"
echo " 操作系统用户:${DM_USER}(密码:${DM_USER_PWD})"
echo " 大小写敏感:${CASE_SENSITIVE} | 字符集:${charset_desc}"
echo "=========================================================="
read -p "配置正确?(y/n):" confirm
[ "${confirm}" != "y" ] && [ "${confirm}" != "Y" ] && log_info "用户取消安装" && exit 0
}
# ==================== 前置检查(仅创建安装必需目录)====================
pre_check() {
log_info "==================== 前置检查(仅创建必需目录)====================="
# 【修复点4】明确要求root用户执行(服务创建必须root权限)
[ "$(id -u)" -ne 0 ] && log_error "【修复要求】请使用root用户执行脚本(系统服务创建需要root权限)"
# 2. 仅创建安装必需目录(解压/安装/挂载)
log_info "创建安装必需目录(解压/安装/挂载)..."
mkdir -p "${UNZIP_DIR}" "${INSTALL_DIR}" || log_error "创建必需目录失败(root权限不足)"
# 3. 压缩包存在校验
[ ! -f "${UNZIP_DIR}/${ZIP_PACKAGE}" ] && log_error "压缩包未找到!请上传${ZIP_PACKAGE}到${UNZIP_DIR}目录"
# 4. 授权文件校验
if [ -n "${DM_KEY_FILE}" ] && [ "${DM_KEY_FILE}" != "" ]; then
log_info "检查授权文件:${DM_KEY_FILE}"
[ ! -f "${DM_KEY_FILE}" ] && log_error "授权文件dm.key不存在!请核对DM_KEY_FILE参数"
if echo "${DM_KEY_FILE}" | grep -q "[[:space:]]"; then
log_error "授权文件路径不能包含空格!请修改DM_KEY_FILE参数"
fi
chmod 644 "${DM_KEY_FILE}"
chown ${DM_USER}:${DM_GROUP} "${DM_KEY_FILE}"
log_info "✅ 授权文件权限配置完成"
fi
# 5. 端口占用检查
log_info "检查端口可用性..."
check_port ${PORT_NUM}
log_info "端口${PORT_NUM}可用"
# 6. 系统资源检查
local mem_total=$(free -g | grep Mem | awk '{print $2}')
[ ${mem_total} -lt 2 ] && log_warn "内存不足2G(官方最低要求),可能导致安装失败"
local disk_free=$(df -P ${INSTALL_DIR} | grep -v Filesystem | awk '{print $4/1024/1024}')
[ $(echo "${disk_free} < 10" | bc) -eq 1 ] && log_error "安装目录磁盘空间不足10G(官方最低要求)"
}
# ==================== 基础环境部署(仅授权必需目录)====================
base_deploy() {
log_info "==================== 基础环境部署(适配目录时机)====================="
# 1. 创建官方强制用户组
log_info "创建用户组${DM_GROUP}..."
if ! grep -q "^${DM_GROUP}:" /etc/group; then
groupadd "${DM_GROUP}" || log_error "用户组${DM_GROUP}创建失败"
log_info "✅ 用户组${DM_GROUP}创建成功"
else
log_info "用户组${DM_GROUP}已存在,跳过"
fi
# 2. 创建数据库专用用户
log_info "创建用户${DM_USER}..."
if ! id -u "${DM_USER}" >/dev/null 2>&1; then
useradd -g "${DM_GROUP}" -m -d "/home/${DM_USER}" -s /bin/bash "${DM_USER}" || log_error "用户${DM_USER}创建失败"
log_info "✅ 用户${DM_USER}创建成功(用户组:${DM_GROUP})"
else
log_info "用户${DM_USER}已存在,跳过"
fi
# 3. 设置dmdba用户密码
echo "${DM_USER_PWD}" | passwd --stdin "${DM_USER}" || log_error "${DM_USER}用户密码设置失败"
log_info "✅ ${DM_USER}用户密码已设置:${DM_USER_PWD}"
# 4. 配置系统资源限制
log_info "配置系统资源限制(/etc/security/limits.conf)..."
if ! grep -q "^${DM_USER} " /etc/security/limits.conf; then
cat >> /etc/security/limits.conf << EOF
# DM8 资源限制(官方规范)
${DM_USER} soft nofile 65536
${DM_USER} hard nofile 65536
${DM_USER} soft nproc 131072
${DM_USER} hard nproc 131072
EOF
fi
su - "${DM_USER}" -c "ulimit -n 65536" >/dev/null 2>&1
log_info "✅ 系统资源限制配置完成"
# 5. 解压压缩包
log_info "解压压缩包${ZIP_PACKAGE}(解压目录:${UNZIP_DIR})..."
cd "${UNZIP_DIR}" || log_error "切换到解压目录${UNZIP_DIR}失败"
unzip -o "${ZIP_PACKAGE}" -d "${UNZIP_DIR}" || log_error "压缩包解压失败(可能是包损坏)"
[ ! -f "${UNZIP_DIR}/${ISO_FILE}" ] && log_error "解压后未找到ISO文件:${UNZIP_DIR}/${ISO_FILE}"
log_info "✅ 压缩包解压成功(ISO路径:${UNZIP_DIR}/${ISO_FILE})"
# 6. 挂载ISO文件
log_info "挂载ISO文件到${MOUNT_DIR}..."
if mount | grep -q "${MOUNT_DIR}"; then
umount "${MOUNT_DIR}" >/dev/null 2>&1 || log_error "卸载已挂载的${MOUNT_DIR}失败"
fi
mount -o loop "${UNZIP_DIR}/${ISO_FILE}" "${MOUNT_DIR}" || log_error "ISO挂载失败(路径:${UNZIP_DIR}/${ISO_FILE})"
log_info "✅ ISO文件挂载成功"
# 7. 仅授权必需目录(安装目录+用户家目录)
log_info "配置必需目录权限..."
chown -R "${DM_USER}:${DM_GROUP}" "${INSTALL_DIR}" "/home/${DM_USER}"
check_dir_perm "${INSTALL_DIR}" 755
log_info "✅ 必需目录权限配置完成"
}
# ==================== (核心) 数据库安装(安装后创建业务目录)====================
db_install() {
log_info "==================== 数据库安装(动态XML静默模式)====================="
# 动态生成XML配置文件(所有参数从基础配置读取,无需手动修改)
local xml_config="/home/${DM_USER}/dm_install.xml"
su - "${DM_USER}" -c "cat > ${xml_config} << EOF
<?xml version=\"1.0\" encoding=\"UTF-8\"?>
<DATABASE>
<LANGUAGE>ZH</LANGUAGE>
<!-- 安装语言:官方强制节点名+取值 -->
<INSTALLER_LANGUAGE>zh_CN</INSTALLER_LANGUAGE>
<!-- 时区:官方数字编码(+08:00=中国标准时间,兼容所有版本) -->
<TIME_ZONE>+08:00</TIME_ZONE>
<!-- 授权文件路径:动态读取DM_KEY_FILE参数 -->
<KEY_FILE>${DM_KEY_FILE}</KEY_FILE>
<!-- 安装类型:官方推荐字符串格式(0 表示安装全部,1 表示安装服务器,2 表示安装客户端。) -->
<INSTALL_TYPE>0</INSTALL_TYPE>
<!-- 安装目录:动态读取INSTALL_DIR参数 -->
<INSTALL_PATH>${INSTALL_DIR}</INSTALL_PATH>
<!-- 自动初始化数据库:动态读取INIT_DB参数 -->
<INIT_DB>${INIT_DB}</INIT_DB>
<!-- 数据库实例参数:动态注入所有配置 -->
<DB_PARAMS>
<!-- 数据目录:动态读取DATA_DIR参数 -->
<PATH>${DATA_DIR}</PATH>
<!-- 数据库名:动态读取DB_NAME参数 -->
<DB_NAME>${DB_NAME}</DB_NAME>
<!-- 实例名:动态读取CURRENT_INSTANCE_NAME -->
<INSTANCE_NAME>${CURRENT_INSTANCE_NAME}</INSTANCE_NAME>
<!-- 数据库端口:动态读取PORT_NUM参数 -->
<PORT_NUM>${PORT_NUM}</PORT_NUM>
<!-- 日志目录:动态读取LOG_DIR参数(无空节点,避免解析错误) -->
<LOG_PATHS>
<LOG_PATH></LOG_PATH>
</LOG_PATHS>
<!-- 扩展页大小:动态读取EXTENT_SIZE参数 -->
<EXTENT_SIZE>${EXTENT_SIZE}</EXTENT_SIZE>
<!-- 页大小:动态读取PAGE_SIZE参数 -->
<PAGE_SIZE>${PAGE_SIZE}</PAGE_SIZE>
<!-- 日志大小:动态读取LOG_SIZE参数 -->
<!-- <LOG_SIZE>${LOG_SIZE}</LOG_SIZE> -->
<!-- 大小写敏感:动态读取CASE_SENSITIVE参数 -->
<CASE_SENSITIVE>${CASE_SENSITIVE}</CASE_SENSITIVE>
<!-- 字符集:动态读取CHARSET参数 -->
<CHARSET>${CHARSET}</CHARSET>
<!-- 新哈希算法:动态读取USE_NEW_HASH参数 -->
<USE_NEW_HASH>${USE_NEW_HASH}</USE_NEW_HASH>
<!-- SYSDBA密码:动态读取SYSDBA_PWD参数 -->
<SYSDBA_PWD>${SYSDBA_PWD}</SYSDBA_PWD>
<!-- SYSSSO密码:动态读取SYSSSO_PWD参数 -->
<SYSSSO_PWD>${SYSSSO_PWD}</SYSSSO_PWD>
<!-- SYSAUDITOR密码:动态读取SYSAUDITOR_PWD参数 -->
<SYSAUDITOR_PWD>${SYSAUDITOR_PWD}</SYSAUDITOR_PWD>
<!-- 加密算法:动态读取ENCRYPT_NAME参数 -->
<ENCRYPT_NAME>${ENCRYPT_NAME}</ENCRYPT_NAME>
</DB_PARAMS>
<!-- 自动创建系统服务:动态读取CREATE_DB_SERVICE参数 -->
<CREATE_DB_SERVICE>N</CREATE_DB_SERVICE>
<!-- 自动启动系统服务:动态读取STARTUP_DB_SERVICE参数 -->
<STARTUP_DB_SERVICE>N</STARTUP_DB_SERVICE>
</DATABASE>
EOF"
# 校验XML配置文件
if [ ! -f "${xml_config}" ]; then
log_error "动态XML配置文件创建失败!请检查/home/${DM_USER}目录权限"
fi
su - "${DM_USER}" -c "sed -i '/^$/d' ${xml_config}"
if ! grep -q "<DATABASE>" "${xml_config}"; then
log_error "XML根节点错误!必须为<DATABASE>(大小写敏感)"
fi
log_info "✅ 动态XML配置文件创建完成(已关闭安装阶段自动创建服务)"
# 执行静默安装(dmdba用户,仅安装软件和初始化实例)
log_info "执行XML静默安装(不创建服务,后续root创建)..."
su - "${DM_USER}" -c "cd ${MOUNT_DIR} && ./DMInstall.bin -q ${xml_config}" || {
umount "${MOUNT_DIR}"
log_error "安装失败!可能原因:1.XML格式错误;2.内存不足;3.安装包损坏;4.授权文件无效"
}
log_info "✅ 数据库软件安装+实例初始化成功"
# 执行官方root收尾脚本
log_info "执行官方root收尾脚本..."
local root_script="${INSTALL_DIR}/script/root/root_installer.sh"
[ ! -f "${root_script}" ] && {
umount "${MOUNT_DIR}"
log_error "未找到官方收尾脚本:${root_script}(安装失败)"
}
${root_script} || {
umount "${MOUNT_DIR}"
log_error "root收尾脚本执行失败,请手动执行:${root_script}"
}
log_info "✅ root收尾脚本执行成功"
# 安装后创建所有业务目录(数据/日志/归档/备份)
log_info "安装后创建业务目录(数据/日志/归档/备份)..."
mkdir -p "${DATA_DIR}" "${ARCHIVE_DIR}" "${BACKUP_DIR}" || log_error "创建业务目录失败"
# 授权业务目录(统一授权给dmdba:dinstall)
chown -R "${DM_USER}:${DM_GROUP}" "${DATA_DIR}" "${ARCHIVE_DIR}" "${BACKUP_DIR}"
check_dir_perm "${DATA_DIR}" 700 # 数据目录仅dmdba访问(安全要求)
check_dir_perm "${ARCHIVE_DIR}" 755
check_dir_perm "${BACKUP_DIR}" 755
log_info "✅ 业务目录创建+授权完成"
# 配置dmdba用户环境变量
log_info "配置${DM_USER}用户环境变量..."
if ! grep -q "export DM_HOME=" "/home/${DM_USER}/.bashrc"; then
cat >> "/home/${DM_USER}/.bashrc" << EOF
# DM8 环境变量(动态配置)
export DM_HOME=${INSTALL_DIR}
export PATH=\$DM_HOME/bin:\$DM_HOME/tool:\$PATH
export LD_LIBRARY_PATH=\$DM_HOME/bin:\$LD_LIBRARY_PATH
EOF
fi
source "/home/${DM_USER}/.bashrc"
log_info "✅ 环境变量配置完成"
# 清理临时XML配置文件
su - "${DM_USER}" -c "rm -f ${xml_config}"
log_info "✅ 临时XML配置文件已清理"
# 【修复点5】调用核心修复函数:root创建系统服务(安装后立即执行)
create_system_service
}
# ==================== 单机数据库配置(简化配置)====================
single_config() {
log_info "==================== 单机数据库配置 ===================="
# 校验实例配置文件
if [ ! -f "${DM_INI_PATH}" ]; then
DM_INI_PATH="${DATA_DIR}/${DB_NAME}/dm.ini"
[ ! -f "${DM_INI_PATH}" ] && log_error "数据库实例未初始化!请检查XML配置中INIT_DB是否为Y"
fi
# 配置本地归档(使用安装后创建的归档目录)
local ARCHIVE_CONFIG="${DATA_DIR}/${DB_NAME}/dmarch.ini"
su - "${DM_USER}" -c "cat > ${ARCHIVE_CONFIG} << EOF
[ARCHIVE1]
ARCH_TYPE = LOCAL
ARCH_DEST = ${ARCHIVE_DIR}
ARCH_FILE_SIZE = 1024
ARCH_SPACE_LIMIT = 0
EOF"
# 修改dm.ini启用归档
su - "${DM_USER}" -c "sed -i 's/^ARCH_INI=.*/ARCH_INI=1/' ${DM_INI_PATH}"
su - "${DM_USER}" -c "sed -i 's/^INSTANCE_NAME=.*/INSTANCE_NAME=${CURRENT_INSTANCE_NAME}/' ${DM_INI_PATH}"
# 【修复点6】使用创建好的系统服务重启(而非手动启动dmserver)
log_info "重启数据库服务..."
local service_name="DmService${CURRENT_INSTANCE_NAME}"
systemctl restart "${service_name}" >/dev/null 2>&1 || log_error "数据库服务重启失败!手动执行:systemctl restart ${service_name}"
sleep 15
log_info "✅ 单机数据库配置完成"
}
# ==================== 防火墙配置(开放数据库端口)====================
firewall_config() {
log_info "配置防火墙规则(开放数据库端口)..."
if command -v firewall-cmd &> /dev/null; then
firewall-cmd --permanent --add-port=${PORT_NUM}/tcp
firewall-cmd --reload
elif command -v iptables &> /dev/null; then
iptables -I INPUT -p tcp --dport ${PORT_NUM} -j ACCEPT
service iptables save >/dev/null 2>&1
else
log_warn "未检测到防火墙工具,已跳过端口开放(需手动配置)"
fi
log_info "✅ 防火墙配置完成"
}
# ==================== 清理与验证(适配业务目录)====================
cleanup_verify() {
# 卸载ISO挂载
umount "${MOUNT_DIR}" >/dev/null 2>&1
log_info "临时文件清理完成"
# 验证安装结果
log_info "==================== 安装结果验证 ===================="
local service_name="DmService${CURRENT_INSTANCE_NAME}"
# 【修复点8】新增服务状态验证(确保修复生效)
log_info "【修复验证】服务状态检查:${service_name}"
if systemctl is-active --quiet "${service_name}"; then
log_info "✅ 【修复成功】服务${service_name}运行正常"
else
log_error "【修复失败】服务${service_name}未运行!状态:$(systemctl status "${service_name}" | grep Active)"
fi
# 验证数据库连接
log_info "单机数据库连接验证(IP:${LOCAL_IP},实例名:${CURRENT_INSTANCE_NAME})..."
su - "${DM_USER}" -c "disql SYSDBA/${SYSDBA_PWD}@${LOCAL_IP}:${PORT_NUM} << EOF
SELECT INSTANCE_NAME, STATUS\$ FROM V\$INSTANCE;
SELECT ARCH_TYPE, ARCH_DEST, STATUS FROM V\$ARCHIVE_DEST;
COMMIT;
EXIT;
EOF"
# 验证标准提示
log_info "✅ 单机数据库验证完成:STATUS$ 显示 OPEN 即为正常"
}
# ==================== 主流程(完整闭环)====================
main() {
log_info "==================== 达梦DM8单机模式安装脚本(修复点标记版)====================="
log_info "【修复说明】核心解决:dmdba用户无权限创建系统服务,改为root手动调用官方脚本创建"
interactive_input # 配置确认+动态参数汇总
pre_check # 前置检查(要求root用户)
base_deploy # 基础环境(用户+依赖+必需目录授权)
db_install # 安装+业务目录创建+调用修复函数创建服务
firewall_config # 防火墙配置
single_config # 单机数据库配置(使用系统服务重启)
cleanup_verify # 清理+服务状态验证(确认修复生效)
# 安装完成提示(标注修复结果)
log_info "=========================================================="
log_info "🎉🎉 达梦DM8 单机数据库安装完成!【修复结果】系统服务创建成功"
log_info "核心信息:"
log_info " 实例名:${CURRENT_INSTANCE_NAME} | 数据库名:${DB_NAME}"
log_info " 连接地址:${LOCAL_IP}:${PORT_NUM}"
log_info " SYSDBA密码:${SYSDBA_PWD}"
log_info " 系统服务:${service_name}(root创建,已启动+开机自启)"
log_info " 服务管理:systemctl [start/stop/status] ${service_name}"
log_info " 业务目录(安装后创建):数据=${DATA_DIR} | 归档=${ARCHIVE_DIR}"
log_info " 解压目录(可删除):${UNZIP_DIR}"
log_info "=========================================================="
}
# 执行主流程
main
JDK1.8
sh
#!/bin/bash
##############################################################################
# 脚本名称:kylin10-install-openjdk8.sh
# 适用系统:麒麟OS 10(x86_64架构)
# 安装内容:java-1.8.0-openjdk.x86_64 + 环境变量配置
# 执行方式:sudo bash 脚本名.sh 或 chmod +x 脚本名.sh && sudo ./脚本名.sh
##############################################################################
# 颜色定义(美化输出)
RED="\033[31m"
GREEN="\033[32m"
YELLOW="\033[33m"
RESET="\033[0m"
# 1. 检查是否以root权限运行(yum安装需root)
if [ "$(id -u)" -ne 0 ]; then
echo -e "${RED}[错误] 请使用root权限运行脚本(sudo ./脚本名.sh)${RESET}"
exit 1
fi
echo -e "${YELLOW}[步骤1/3] 正在安装java-1.8.0-openjdk.x86_64(可查看实时进度)...${RESET}"
# 2. 直接安装指定版本OpenJDK(含开发工具包)- 保留输出,显示进度
yum install -y java-1.8.0-openjdk.x86_64 java-1.8.0-openjdk-devel.x86_64
if [ $? -ne 0 ]; then
echo -e "${RED}[错误] OpenJDK安装失败!可能原因:${RESET}"
echo -e "${RED}1. yum源未包含该包(java-1.8.0-openjdk.x86_64)${RESET}"
echo -e "${RED}2. 网络无法连接yum源${RESET}"
echo -e "${RED}3. 依赖包缺失${RESET}"
exit 1
fi
echo -e "\n${YELLOW}[步骤2/3] 正在配置环境变量...${RESET}"
# 3. 自动查找JAVA_HOME路径(OpenJDK默认安装在/usr/lib/jvm/下)
JAVA_HOME=$(find /usr/lib/jvm -name "java-1.8.0-openjdk-*" 2>/dev/null | head -n 1)
if [ -z "$JAVA_HOME" ]; then
JAVA_HOME=$(find /usr/lib/jvm -name "jre-1.8.0-openjdk-*" 2>/dev/null | head -n 1)
fi
# 验证JAVA_HOME是否存在
if [ -z "$JAVA_HOME" ]; then
echo -e "${RED}[错误] 未找到JAVA_HOME路径,安装可能不完整${RESET}"
exit 1
fi
# 配置环境变量(写入/etc/profile,所有用户永久生效)
ENV_CONFIG="
# Java 1.8.0 OpenJDK 环境变量
export JAVA_HOME=$JAVA_HOME
export JRE_HOME=\$JAVA_HOME/jre
export CLASSPATH=.:\$JAVA_HOME/lib:\$JRE_HOME/lib
export PATH=\$JAVA_HOME/bin:\$PATH
"
# 检查环境变量是否已存在,避免重复配置
if ! grep -q "JAVA_HOME=$JAVA_HOME" /etc/profile; then
echo "$ENV_CONFIG" >> /etc/profile
echo -e "${GREEN}[成功] 环境变量已写入/etc/profile${RESET}"
else
echo -e "${YELLOW}[提示] 环境变量已存在,无需重复配置${RESET}"
fi
# 立即加载环境变量(当前终端生效)
source /etc/profile > /dev/null 2>&1
echo -e "\n${YELLOW}[步骤3/3] 正在验证安装结果...${RESET}"
# 4. 验证Java版本(显示完整版本信息)
echo -e "${YELLOW}[信息] Java版本信息:${RESET}"
java -version 2>&1
echo -e "${YELLOW}[信息] Javac版本信息:${RESET}"
javac -version 2>&1
# 二次验证版本号是否为1.8.x
JAVA_VERSION=$(java -version 2>&1 | grep "1.8.0_" | awk '{print $3}' | sed 's/"//g')
if [ -n "$JAVA_VERSION" ]; then
echo -e "\n${GREEN}[成功] Java 1.8.0 OpenJDK 安装完成!${RESET}"
echo -e "${GREEN}=====================================${RESET}"
echo -e "${GREEN}JAVA_HOME: $JAVA_HOME${RESET}"
echo -e "${GREEN}Java 版本: $JAVA_VERSION${RESET}"
echo -e "${GREEN}=====================================${RESET}"
echo -e "${YELLOW}[提示] 新终端会自动加载环境变量,当前终端已生效${RESET}"
else
echo -e "\n${RED}[错误] Java版本验证失败,请手动执行 source /etc/profile 后重试java -version${RESET}"
exit 1
fi
Nginx
sh
#!/bin/bash
##############################################################################
# 麒麟OS 单机Nginx一键安装脚本(保留原有配置 + .pfx证书版)
# 核心特性:pfx自动转key/crt + Nginx yum安装 + 动态负载均衡 + 防火墙放行
# 适用场景:单机部署,无需双机高可用,支持逗号分割配置多后端节点
##############################################################################
# 检查是否以root用户执行
if [ "$(id -u)" -ne 0 ]; then
echo "错误:请使用root用户执行脚本(sudo -i 切换后再运行)"
exit 1
fi
# ====================== 核心配置项(重点:负载均衡地址支持逗号分割)======================
# 1. 网络相关(仅保留单机必要配置)
NET_INTERFACE="enp4s1" # 服务器网卡名称(通过 ip addr 查看,无需修改)
DOMAIN="nginx" # 你的域名(原VIP对应的域名,直接作为访问域名)
# 2. SSL证书配置(保留你的原有PFX配置,自动转换)
PFX_FILE_PATH="/root/ssl/CN=nginx-p.pfx" # 你的.pfx证书文件路径(无需修改)
PFX_PASSWORD="r#1234" # 你的.pfx证书密码(无需修改,含特殊字符已保留)
SSL_NGINX_DIR="/etc/nginx/ssl" # 转换后key/crt存放目录(无需修改)
# 3. Nginx端口配置(保留原有端口)
HTTP_PORT="80" # HTTP端口(自动跳转HTTPS,无需修改)
HTTPS_PORT="443" # HTTPS端口(无需修改)
# 4. 动态负载均衡配置(核心变更:逗号分割多后端地址,格式:IP:端口,IP:端口)
BACKEND_SERVERS="10.xx.xxx.1:8080,10.xx.xxx.2:8080" # 负载均衡节点(支持任意多个,逗号分隔)
LOAD_BALANCE_STRATEGY="ip_hash" # 负载均衡策略(默认ip_hash,可选:round_robin/least_conn/ip_hash)
# ============================================================================
# 输出日志函数
info() {
echo -e "\033[32m[INFO] $1\033[0m"
}
error() {
echo -e "\033[31m[ERROR] $1\033[0m"
exit 1
}
# 预检查:验证单机必要配置和依赖(新增负载均衡节点格式校验)
pre_check() {
info "开始预检查..."
# 检查.pfx证书文件(保留原有路径验证)
if [ ! -f "${PFX_FILE_PATH}" ]; then
error "pfx证书文件不存在:${PFX_FILE_PATH},请确认文件路径正确"
fi
# 检查openssl工具(证书转换必需)
if ! command -v openssl &> /dev/null; then
info "未找到openssl工具,正在自动安装..."
yum install -y openssl &> /dev/null || error "openssl安装失败,请手动执行:yum install -y openssl"
fi
# 检查网卡(保留原有网卡验证)
if ! ip link show "${NET_INTERFACE}" > /dev/null 2>&1; then
error "网卡 ${NET_INTERFACE} 不存在!通过 ip addr 查看实际网卡名称"
fi
# 检查端口是否被占用
if netstat -tulpn | grep -q ":${HTTP_PORT}"; then
OCCUPY_PROC=$(netstat -tulpn | grep ":${HTTP_PORT}" | awk '{print $7}')
error "HTTP端口 ${HTTP_PORT} 已被占用!占用进程:${OCCUPY_PROC},请停止进程或修改端口"
fi
if netstat -tulpn | grep -q ":${HTTPS_PORT}"; then
OCCUPY_PROC=$(netstat -tulpn | grep ":${HTTPS_PORT}" | awk '{print $7}')
error "HTTPS端口 ${HTTPS_PORT} 已被占用!占用进程:${OCCUPY_PROC},请停止进程或修改端口"
fi
# 检查yum源可用性
if ! yum repolist &> /dev/null; then
error "yum源不可用,请先修复麒麟OS的yum配置(本地源/官方源)"
fi
# 卸载旧版本Nginx(避免冲突)
if command -v nginx &> /dev/null; then
info "检测到已安装Nginx,正在卸载旧版本..."
systemctl stop nginx &> /dev/null
yum remove -y nginx &> /dev/null || error "旧版本Nginx卸载失败,请手动执行:yum remove -y nginx"
fi
# 新增:校验负载均衡节点格式(必须是 IP:端口 格式,逗号分割,自动去除空格)
if [ -z "${BACKEND_SERVERS}" ]; then
error "负载均衡节点配置为空!请在 BACKEND_SERVERS 中填写至少一个节点(格式:IP:端口)"
fi
# 去除节点前后空格,再分割
CLEAN_SERVERS=$(echo "${BACKEND_SERVERS}" | tr -d ' ')
IFS=',' read -ra SERVERS <<< "${CLEAN_SERVERS}"
for server in "${SERVERS[@]}"; do
if ! echo "${server}" | grep -E '^[0-9]+\.[0-9]+\.[0-9]+\.[0-9]+:[0-9]+$' &> /dev/null; then
error "负载均衡节点格式错误:${server},正确格式:IP:端口(示例:10.125.179.1:8080),请检查是否有多余字符"
fi
done
# 校验负载均衡策略合法性
if [[ ! "${LOAD_BALANCE_STRATEGY}" =~ ^(round_robin|least_conn|ip_hash)$ ]]; then
error "负载均衡策略错误:${LOAD_BALANCE_STRATEGY},可选值:round_robin/least_conn/ip_hash"
fi
info "预检查通过"
}
# 1. 安装核心依赖(仅保留单机必需组件,去掉Keepalived)
install_deps() {
info "安装核心依赖..."
yum install -y nginx firewalld net-tools openssl openssl-devel pcre-devel zlib-devel || {
error "依赖安装失败,请检查yum源"
}
info "依赖安装完成"
}
# 2. pfx证书自动转换(完全保留原有逻辑,无需修改)
convert_pfx_to_key_crt() {
info "开始转换.pfx证书为key/crt格式..."
# 创建证书目录(权限700,仅root可访问)
mkdir -p ${SSL_NGINX_DIR} || error "创建证书目录失败"
chmod 700 ${SSL_NGINX_DIR}
# 定义转换后的文件路径
KEY_FILE="${SSL_NGINX_DIR}/server.key" # 私钥
CRT_FILE="${SSL_NGINX_DIR}/server.crt" # 公钥证书
# 1. 从pfx提取私钥(保留密码处理逻辑)
info "提取私钥(server.key)..."
if [ -z "${PFX_PASSWORD}" ]; then
openssl pkcs12 -in "${PFX_FILE_PATH}" -nocerts -nodes -out "${KEY_FILE}" -passin pass: || {
error "私钥提取失败,请检查pfx文件是否无密码"
}
else
openssl pkcs12 -in "${PFX_FILE_PATH}" -nocerts -nodes -out "${KEY_FILE}" -passin pass:"${PFX_PASSWORD}" || {
error "私钥提取失败,请检查pfx密码是否正确(当前密码:${PFX_PASSWORD})"
}
fi
# 2. 从pfx提取公钥证书
info "提取证书(server.crt)..."
if [ -z "${PFX_PASSWORD}" ]; then
openssl pkcs12 -in "${PFX_FILE_PATH}" -nokeys -out "${CRT_FILE}" -passin pass: || {
error "证书提取失败"
}
else
openssl pkcs12 -in "${PFX_FILE_PATH}" -nokeys -out "${CRT_FILE}" -passin pass:"${PFX_PASSWORD}" || {
error "证书提取失败,请检查pfx密码是否正确"
}
fi
# 3. 清理证书格式(确保Nginx识别)
sed -i '/Bag Attributes/d' "${CRT_FILE}"
sed -i '/localKeyID/d' "${CRT_FILE}"
sed -i '/^$/d' "${CRT_FILE}"
# 4. 严格限制文件权限(安全最佳实践)
chmod 600 "${KEY_FILE}" "${CRT_FILE}"
chown root:root "${KEY_FILE}" "${CRT_FILE}"
# 验证转换结果
if [ -f "${KEY_FILE}" ] && [ -f "${CRT_FILE}" ]; then
info "pfx证书转换成功!"
info "私钥:${KEY_FILE}"
info "证书:${CRT_FILE}"
else
error "pfx证书转换失败,请检查pfx文件完整性和密码"
fi
}
# 3. 配置Nginx(修复动态生成upstream的语法问题)
config_nginx() {
info "配置Nginx(动态生成负载均衡配置)..."
NGINX_CONF="/etc/nginx/nginx.conf"
DEFAULT_CONF="/etc/nginx/conf.d/default.conf"
# 备份默认配置
[ -f "${DEFAULT_CONF}" ] && mv -f "${DEFAULT_CONF}" "${DEFAULT_CONF}.bak.$(date +%Y%m%d%H%M%S)"
[ -f "${NGINX_CONF}" ] && mv -f "${NGINX_CONF}" "${NGINX_CONF}.bak.$(date +%Y%m%d%H%M%S)"
# 生成主配置(保留原有主配置逻辑,未修改)
cat > "${NGINX_CONF}" << EOF
user nginx;
worker_processes auto;
error_log /var/log/nginx/error.log warn;
pid /var/run/nginx.pid;
events {
worker_connections 1024;
}
http {
include /etc/nginx/mime.types;
default_type application/octet-stream;
log_format main '\$remote_addr - \$remote_user [\$time_local] "\$request" '
'\$status \$body_bytes_sent "\$http_referer" '
'"\$http_user_agent" "\$http_x_forwarded_for"';
access_log /var/log/nginx/access.log main;
sendfile on;
tcp_nopush on;
tcp_nodelay on;
keepalive_timeout 65;
gzip on;
gzip_min_length 1k;
gzip_buffers 4 16k;
gzip_comp_level 6;
gzip_types text/plain text/css application/json application/javascript text/xml application/xml application/xml+rss text/javascript;
include /etc/nginx/conf.d/*.conf;
}
EOF
# 初始化站点配置文件(先写入HTTP跳转和upstream开头)
cat > "${DEFAULT_CONF}" << EOF
# HTTP强制跳转HTTPS
server {
listen ${HTTP_PORT};
server_name nginx-p www.nginx-p;
access_log /var/log/nginx/http_access.log main;
return 301 https://\$host\$request_uri;
}
# 动态负载均衡配置(从BACKEND_SERVERS变量生成,策略:${LOAD_BALANCE_STRATEGY})
upstream nginx_servers {
${LOAD_BALANCE_STRATEGY};
EOF
# 核心逻辑:解析逗号分割的后端节点(自动去除空格),动态添加到upstream
CLEAN_SERVERS=$(echo "${BACKEND_SERVERS}" | tr -d ' ') # 去除所有空格,避免配置错误
IFS=',' read -ra SERVERS <<< "${CLEAN_SERVERS}"
for server in "${SERVERS[@]}"; do
# 确保每个server节点格式正确,结尾加分号
echo " server ${server};" >> "${DEFAULT_CONF}"
done
# 继续拼接剩余配置(完全保留原有内容,无修改)
cat >> "${DEFAULT_CONF}" << EOF
}
# HTTPS核心配置(保留原有SSL优化参数)
server {
listen ${HTTPS_PORT} ssl http2;
server_name nginx-p www.nginx-p;
# 引用转换后的证书和私钥(路径不变)
ssl_certificate ${SSL_NGINX_DIR}/server.crt;
ssl_certificate_key ${SSL_NGINX_DIR}/server.key;
# SSL安全优化(保留原有配置)
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
ssl_stapling on;
ssl_stapling_verify on;
# resolver 8.8.8.8 114.114.114.114 valid=300s;
# resolver_timeout 5s;
# 网站根目录(保留原有路径)
root /usr/share/nginx/html;
index index.html index.htm;
# 静态资源访问(保留原有逻辑)
location / {
try_files \$uri \$uri/ /index.html;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
# API请求转发到后端服务器(保留你的原有配置,目标指向动态upstream)
location /server-api {
proxy_connect_timeout 6;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_set_header X-Real-IP \$remote_addr;
proxy_set_header Client-IP \$remote_addr;
proxy_set_header Host \$http_host;
proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
client_max_body_size 500m;
proxy_pass http://nginx_servers;
proxy_redirect default;
}
# API请求转发到后端服务器(保留你的原有注释,按需启用)
location /api/ {
rewrite ^/api/(.*) /\$1 break;
# proxy_pass ;
# proxy_set_header Host \$host;
# proxy_set_header X-Real-IP \$remote_addr;
# proxy_set_header X-Forwarded-For \$proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto \$scheme;
}
# 错误页面(保留原有配置)
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
EOF
# 验证Nginx配置语法(关键步骤,避免配置错误)
nginx -t || error "Nginx配置语法错误!请检查证书路径或负载均衡节点配置(错误日志:/var/log/nginx/error.log)"
info "Nginx配置完成(动态负载均衡节点已生成)"
}
# 4. 配置防火墙(放行80/443端口,去掉VRRP协议)
config_firewall() {
info "配置防火墙(放行HTTP/HTTPS端口)..."
# 启动并设置防火墙开机自启
systemctl start firewalld &> /dev/null
systemctl enable firewalld &> /dev/null
# 放行HTTP/HTTPS端口(永久生效)
firewall-cmd --permanent --add-port=${HTTP_PORT}/tcp &> /dev/null
firewall-cmd --permanent --add-port=${HTTPS_PORT}/tcp &> /dev/null
firewall-cmd --reload &> /dev/null
# 永久关闭SELinux(避免拦截Nginx访问)
setenforce 0 &> /dev/null
sed -i 's/^SELINUX=enforcing/SELINUX=disabled/' /etc/selinux/config
info "防火墙配置完成(已放行 ${HTTP_PORT}/${HTTPS_PORT} 端口)"
}
# 5. 启动Nginx并设置开机自启(仅启动Nginx,去掉Keepalived)
start_nginx() {
info "启动Nginx并设置开机自启..."
systemctl enable --now nginx || {
error "Nginx启动失败!查看详细日志:journalctl -u nginx -f"
}
# 验证启动状态
sleep 2
if systemctl is-active --quiet nginx; then
info "Nginx启动成功(运行中)"
else
error "Nginx启动异常停止!查看错误日志:/var/log/nginx/error.log"
fi
}
# 6. 验证安装结果(更新负载均衡信息展示)
verify_install() {
info "======================================"
echo -e "\033[32m[SUCCESS] 单机Nginx安装完成!\033[0m"
echo -e "======================================"
echo -e "📌 核心信息:"
echo -e " Nginx版本:$(nginx -v 2>&1 | awk -F '/' '{print $2}')"
echo -e " 访问域名:https://nginx-p"
echo -e " 配置文件:/etc/nginx/conf.d/default.conf"
echo -e " 证书目录:${SSL_NGINX_DIR}"
echo -e " 网站根目录:/usr/share/nginx/html"
echo -e " 负载均衡策略:${LOAD_BALANCE_STRATEGY}"
echo -e " 后端节点:${BACKEND_SERVERS}"
echo -e " 转发规则:/server-api → http://nginx_servers"
echo -e "\n📌 常用命令:"
echo -e " 启动:systemctl start nginx"
echo -e " 停止:systemctl stop nginx"
echo -e " 重启:systemctl restart nginx"
echo -e " 查看日志:tail -f /var/log/nginx/access.log"
echo -e " 验证配置:nginx -t"
echo -e "======================================"
}
# 主执行流程(去掉双机相关步骤,仅保留单机流程)
main() {
pre_check
install_deps
convert_pfx_to_key_crt
config_nginx
config_firewall
start_nginx
verify_install
# 跳转到Nginx配置目录,方便后续修改
cd /etc/nginx || error "切换到配置目录失败"
echo -e "\033[33m当前目录:$(pwd)(Nginx核心配置目录)\033[0m"
}
# 执行主流程
main
Nginx config配置,带负载均衡
lua
# HTTP强制跳转HTTPS
server {
listen 80;
server_name xxx www.xxx;
access_log /var/log/nginx/http_access.log main;
return 301 https://$host$request_uri;
}
upstream remote_servers {
server 127.0.0.1:8080;
server 127.0.0.2:8080;
server 127.0.0.3:8080;
ip_hash;
}
# HTTPS核心配置
server {
listen 443 ssl http2;
server_name xxx www.xxx;
# 引用转换后的证书和私钥
ssl_certificate /etc/nginx/ssl/server.crt;
ssl_certificate_key /etc/nginx/ssl/server.key;
# SSL安全优化
ssl_protocols TLSv1.2 TLSv1.3;
ssl_prefer_server_ciphers on;
ssl_ciphers "EECDH+AESGCM:EDH+AESGCM:AES256+EECDH:AES256+EDH";
ssl_session_cache shared:SSL:10m;
ssl_session_timeout 10m;
ssl_session_tickets off;
# ssl_stapling on;
# ssl_stapling_verify on;
# resolver 8.8.8.8 114.114.114.114 valid=300s;
# resolver_timeout 5s;
# 网站根目录
root /usr/share/nginx/html;
index index.html index.htm;
# 静态资源访问
location / {
try_files $uri $uri/ /index.html;
add_header Strict-Transport-Security "max-age=31536000; includeSubDomains" always;
}
# API请求转发到后端服务器(目标已替换为变量)
location /server-api {
proxy_connect_timeout 6;
proxy_send_timeout 60;
proxy_read_timeout 60;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header Client-IP $remote_addr;
proxy_set_header Host $http_host;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
client_max_body_size 500m;
proxy_pass http://remote_servers;
proxy_redirect default;
}
# API请求转发到后端服务器(按需启用)
location /api/ {
rewrite ^/api/(.*) /$1 break;
# proxy_pass ;
# proxy_set_header Host $host;
# proxy_set_header X-Real-IP $remote_addr;
# proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
# proxy_set_header X-Forwarded-Proto $scheme;
}
# 错误页面
error_page 500 502 503 504 /50x.html;
location = /50x.html {
root /usr/share/nginx/html;
}
}
vsftpd 存储
sh
#!/bin/bash
###########################################################################
# 脚本功能:银河麒麟V10 一键搭建 vsftpd 服务(存储目录:/data/ftproot/[用户名])
# 依赖环境:root权限 + 网络通畅(yum安装依赖)
# 使用说明:1. 修改脚本内自定义配置区;2. chmod +x vsftpd_install.sh;3. ./vsftpd_install.sh
# 核心特性:自定义用户名密码+无交互+用户重建+鉴权修复(彻底解决530错误)
###########################################################################
# ===================== 自定义配置区(必须修改后执行!)=====================
FTP_USER="ftpuser" # 自定义FTP用户名(字母、数字、下划线、短横线,3-32位)
FTP_PASS="FTP_PASS12312" # 自定义FTP密码(≥6位,字母+数字+特殊字符,符合系统策略)
FTP_ROOT="/data/ftproot" # 存储根目录(最终用户目录:/data/ftproot/$FTP_USER)
# =========================================================================
# 检查是否为root用户
if [ "$(id -u)" -ne 0 ]; then
echo "ERROR:必须使用 root 用户执行!"
exit 1
fi
# 验证用户名合法性
if ! echo "$FTP_USER" | grep -qE '^[a-zA-Z0-9_-]{3,32}$'; then
echo "ERROR:用户名不合法!仅支持字母、数字、下划线、短横线,长度3-32位"
exit 1
fi
# 验证密码合法性
if [ ${#FTP_PASS} -lt 6 ] || ! echo "$FTP_PASS" | grep -qE '[a-zA-Z]' || ! echo "$FTP_PASS" | grep -qE '[0-9]'; then
echo "ERROR:密码不合法!建议≥6位,必须包含字母+数字,可选特殊字符(如FtP@123456)"
exit 1
fi
# 最终用户存储目录
FTP_USER_DIR="$FTP_ROOT/$FTP_USER"
echo "========================================"
echo "开始部署 vsftpd 服务"
echo "FTP用户名:$FTP_USER"
echo "存储目录:$FTP_USER_DIR"
echo "========================================"
# 第一步:安装 vsftpd 并启动服务
echo -e "\n1/7 安装 vsftpd 服务..."
if rpm -q vsftpd &> /dev/null; then
echo "vsftpd 已安装,跳过安装步骤"
else
yum install -y vsftpd || { echo "ERROR:vsftpd 安装失败!"; exit 1; }
fi
# 设置开机自启并启动服务
echo "启动 vsftpd 服务..."
systemctl enable --now vsftpd &> /dev/null
if systemctl is-active vsftpd &> /dev/null; then
echo "vsftpd 服务启动成功"
else
echo "ERROR:vsftpd 服务启动失败!"
exit 1
fi
# 第二步:配置防火墙
echo -e "\n2/7 配置防火墙规则..."
firewall-cmd --permanent --zone=public --add-service=ftp &> /dev/null
firewall-cmd --permanent --zone=public --add-port=30000-31000/tcp &> /dev/null
firewall-cmd --reload &> /dev/null
echo "防火墙配置完成(放行21端口 + 30000-31000端口)"
# 第三步:删除已存在用户+清理目录
echo -e "\n3/7 处理FTP用户和存储目录..."
if id -u "$FTP_USER" &> /dev/null; then
echo "用户 $FTP_USER 已存在,正在删除旧用户及数据..."
userdel -rf "$FTP_USER" &> /dev/null
rm -rf "$FTP_USER_DIR" &> /dev/null
echo "旧用户 $FTP_USER 及关联数据删除完成"
fi
# 重新创建存储目录
mkdir -p "$FTP_USER_DIR" &> /dev/null
echo "存储目录创建完成:$FTP_USER_DIR"
# 重新创建FTP用户(nologin shell)
useradd -d "$FTP_USER_DIR" -g ftp -s /sbin/nologin "$FTP_USER" &> /dev/null
if [ $? -eq 0 ]; then
echo "FTP用户 $FTP_USER 重新创建完成"
else
echo "ERROR:创建用户 $FTP_USER 失败!"
exit 1
fi
# 设置目录权限
chown -R "$FTP_USER:ftp" "$FTP_USER_DIR" &> /dev/null
chmod -R 775 "$FTP_USER_DIR" &> /dev/null
echo "目录权限配置完成($FTP_USER 用户拥有读写权限)"
# 第四步:设置FTP用户密码(无交互)
echo -e "\n4/7 设置 FTP 用户密码..."
echo "$FTP_USER:$FTP_PASS" | chpasswd &> /dev/null
if [ $? -eq 0 ]; then
echo "密码设置成功(密码:$FTP_PASS)"
else
echo "ERROR:密码设置失败!请检查密码是否符合系统密码策略"
exit 1
fi
# 第五步:修改 vsftpd 核心配置
echo -e "\n5/7 配置 vsftpd 服务参数..."
if [ ! -f /etc/vsftpd/vsftpd.conf.bak ]; then
cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak &> /dev/null
echo "原配置文件备份:/etc/vsftpd/vsftpd.conf.bak"
fi
# 核心配置(禁止匿名+被动模式+允许本地用户登录)
sed -i \
-e 's/^anonymous_enable=YES/anonymous_enable=NO/' \
-e 's/^#local_enable=YES/local_enable=YES/' \
-e 's/^#write_enable=YES/write_enable=YES/' \
/etc/vsftpd/vsftpd.conf
# 追加被动模式及优化配置
cat >> /etc/vsftpd/vsftpd.conf << EOF
# 被动模式配置(解决外网访问问题)
pasv_enable=YES
pasv_min_port=30000
pasv_max_port=31000
pasv_address=0.0.0.0
# 允许本地用户读写
local_umask=022
# 传输优化
local_max_rate=0
pasv_promiscuous=YES
# 禁用SELinux干扰(若启用SELinux)
allow_writeable_chroot=YES
EOF
echo "vsftpd 核心配置修改完成"
# 第六步:修复PAM鉴权(彻底解决530错误,关键修正!)
echo -e "\n6/7 修复PAM鉴权配置(解决nologin用户530错误)..."
# 备份PAM配置(仅备份一次)
if [ ! -f /etc/pam.d/vsftpd.bak ]; then
cp /etc/pam.d/vsftpd /etc/pam.d/vsftpd.bak &> /dev/null
echo "PAM原配置备份:/etc/pam.d/vsftpd.bak"
fi
# 正确的PAM配置(重点修正)
# 1. 注释 pam_shells.so(不检查shell类型,允许nologin)
# 2. 移除错误的 pam_nologin.so(该模块禁止nologin用户登录)
# 3. 确保 pam_unix.so 正常加载(本地用户密码鉴权)
sed -i \
-e 's/^auth required pam_shells.so/#auth required pam_shells.so/' \
-e '/^auth required pam_nologin.so/d' \
/etc/pam.d/vsftpd
# 确保PAM配置包含本地用户鉴权(防止配置缺失)
grep -q "auth sufficient pam_unix.so" /etc/pam.d/vsftpd || {
echo "auth sufficient pam_unix.so nullok_secure" >> /etc/pam.d/vsftpd
}
grep -q "account sufficient pam_unix.so" /etc/pam.d/vsftpd || {
echo "account sufficient pam_unix.so" >> /etc/pam.d/vsftpd
}
echo "PAM鉴权配置修复完成(已适配nologin用户)"
# 第七步:补充/etc/shells(防止部分系统nologin不在shell列表)
echo -e "\n7/7 补充shell列表(避免鉴权遗漏)..."
if ! grep -q "/sbin/nologin" /etc/shells; then
echo "/sbin/nologin" >> /etc/shells
echo "已将 /sbin/nologin 添加到 /etc/shells"
else
echo "/sbin/nologin 已在 shell 列表中,跳过"
fi
# 重启 vsftpd 服务生效
echo -e "\n========================================"
echo "重启 vsftpd 服务应用所有配置..."
systemctl restart vsftpd &> /dev/null
# 验证服务状态并输出连接信息
if systemctl is-active vsftpd &> /dev/null; then
echo -e "\n✅ vsftpd 服务部署完成!(已彻底解决530鉴权错误)"
echo -e "\n📋 连接信息:"
echo "FTP服务器地址:服务器IP"
echo "FTP用户名:$FTP_USER"
echo "FTP密码:$FTP_PASS"
echo "存储目录:$FTP_USER_DIR"
echo "端口:21(控制端口)、30000-31000(数据端口)"
echo -e "\n💡 测试命令(服务器本地验证):"
echo "ftp -inv 服务器IP"
echo "user $FTP_USER $FTP_PASS" # 直接执行该命令登录,无需手动输入
echo "put 本地文件路径 # 测试上传"
echo "get 服务器文件路径 # 测试下载"
echo -e "\n⚠️ 安全提示:"
echo "1. 执行 chmod 600 vsftpd_install.sh 保护脚本(避免密码泄露)"
echo "2. 生产环境建议定期更新密码(修改脚本 FTP_PASS 后重新执行)"
echo "====================如果不能访问修改一下配置==================================="
echo "1. vi /etc/pam.d/vsftpd"
echo "2. 注释掉(应该在第2行) auth required pam_shells.so"
echo "3. 在最后一行增加 auth required pam_nologin.so"
echo "4. 重新启动 systemctl restart vsftpd"
else
echo -e "\n❌ vsftpd 服务部署失败!"
exit 1
fi
硬盘挂载
sh
#!/bin/bash
# 麒麟OS10 一键硬盘挂载脚本
# 支持自定义硬盘设备名和挂载目录
# 运行方式:sudo bash mount_disk.sh [硬盘设备名] [挂载目录]
# 示例:sudo bash mount_disk.sh /dev/sdb1 /data
##############################################################################
# 基础检查(必须root权限+麒麟OS10)
##############################################################################
if [ "$(id -u)" -ne 0 ]; then
echo -e "\033[31m错误:请使用root权限运行(sudo bash $0)\033[0m"
exit 1
fi
##############################################################################
# 参数处理(支持命令行传参或交互输入)
##############################################################################
# 若未传参,交互询问用户
if [ $# -ne 2 ]; then
echo -e "\033[34m=======================================\033[0m"
echo -e "\033[34m 麒麟OS10 硬盘一键挂载脚本 \033[0m"
echo -e "\033[34m=======================================\033[0m"
# 询问硬盘设备名
read -p "请输入未挂载的硬盘设备名(例:/dev/sdb1、/dev/vdb):" DISK_DEV
if [ -z "$DISK_DEV" ]; then
echo -e "\033[31m错误:硬盘设备名不能为空\033[0m"
exit 1
fi
# 询问挂载目录
read -p "请输入挂载目录(例:/data、/mnt/disk1):" MOUNT_DIR
if [ -z "$MOUNT_DIR" ]; then
echo -e "\033[31m错误:挂载目录不能为空\033[0m"
exit 1
fi
else
# 命令行传参模式
DISK_DEV=$1
MOUNT_DIR=$2
fi
##############################################################################
# 前置检查(避免操作失误)
##############################################################################
echo -e "\033[34m正在执行前置检查...\033[0m"
# 1. 检查硬盘设备是否存在
if [ ! -b "$DISK_DEV" ]; then
echo -e "\033[31m错误:硬盘设备 $DISK_DEV 不存在\033[0m"
echo -e "提示:可通过以下命令查看可用硬盘:fdisk -l 或 lsblk"
exit 1
fi
# 2. 检查硬盘是否已挂载
if mount | grep -q "$DISK_DEV"; then
echo -e "\033[31m错误:硬盘 $DISK_DEV 已挂载,无需重复操作\033[0m"
echo -e "当前挂载点:$(mount | grep "$DISK_DEV" | awk '{print $3}')"
exit 1
fi
# 3. 检查挂载目录是否已存在(存在则提示确认)
if [ -d "$MOUNT_DIR" ]; then
read -p "警告:挂载目录 $MOUNT_DIR 已存在,是否继续(数据不会丢失,y/n)?" CONFIRM
if [ "$CONFIRM" != "y" ] && [ "$CONFIRM" != "Y" ]; then
echo "操作已取消"
exit 0
fi
else
# 不存在则创建目录(含父目录)
echo -e "正在创建挂载目录:$MOUNT_DIR"
mkdir -p "$MOUNT_DIR" || {
echo -e "\033[31m错误:创建挂载目录 $MOUNT_DIR 失败\033[0m"
exit 1
}
fi
# 4. 检查硬盘是否需要格式化(无文件系统则提示格式化)
if ! blkid "$DISK_DEV" | grep -q "TYPE"; then
echo -e "\033[33m警告:硬盘 $DISK_DEV 未检测到文件系统,需要格式化后才能挂载\033[0m"
read -p "是否立即格式化(会清除硬盘所有数据!建议先备份,y/n)?" FORMAT_CONFIRM
if [ "$FORMAT_CONFIRM" = "y" ] || [ "$FORMAT_CONFIRM" = "Y" ]; then
# 默认为ext4格式(麒麟OS推荐),支持自定义格式
read -p "请输入文件系统格式(默认:ext4,支持ext3/xfs/btrfs):" FS_TYPE
FS_TYPE=${FS_TYPE:-ext4}
echo -e "正在格式化 $DISK_DEV 为 $FS_TYPE 格式...(可能需要几分钟)"
case $FS_TYPE in
ext3|ext4) mkfs.$FS_TYPE -F "$DISK_DEV" ;;
xfs) mkfs.xfs -f "$DISK_DEV" ;;
btrfs) mkfs.btrfs -f "$DISK_DEV" ;;
*)
echo -e "\033[31m错误:不支持的文件系统格式 $FS_TYPE\033[0m"
exit 1
;;
esac
# 格式化结果检查
if [ $? -ne 0 ]; then
echo -e "\033[31m错误:格式化 $DISK_DEV 失败\033[0m"
exit 1
fi
else
echo -e "\033[31m错误:未格式化的硬盘无法挂载,操作已取消\033[0m"
exit 1
fi
fi
##############################################################################
# 执行挂载操作
##############################################################################
echo -e "\033[34m正在执行挂载操作...\033[0m"
# 临时挂载(立即生效)
mount "$DISK_DEV" "$MOUNT_DIR" || {
echo -e "\033[31m错误:挂载 $DISK_DEV 到 $MOUNT_DIR 失败\033[0m"
echo -e "提示:检查硬盘格式与系统兼容性,或查看日志:dmesg | grep mount"
exit 1
}
# 获取硬盘UUID(用于fstab开机自启,比设备名更稳定)
DISK_UUID=$(blkid "$DISK_DEV" | grep -oP 'UUID="\K[^"]+')
if [ -z "$DISK_UUID" ]; then
echo -e "\033[31m错误:获取硬盘UUID失败,无法设置开机自启\033[0m"
echo -e "临时挂载已成功,但重启后会失效,请手动配置fstab"
exit 1
fi
# 获取文件系统类型
FS_TYPE=$(blkid "$DISK_DEV" | grep -oP 'TYPE="\K[^"]+')
##############################################################################
# 配置开机自启(fstab)
##############################################################################
echo -e "\033[34m正在配置开机自启...\033[0m"
# 备份fstab(避免配置错误)
FSTAB_BACKUP="/etc/fstab.bak.$(date +%Y%m%d%H%M%S)"
cp /etc/fstab "$FSTAB_BACKUP" || {
echo -e "\033[33m警告:备份fstab失败,但仍将继续配置开机自启\033[0m"
}
# 检查fstab中是否已存在该硬盘配置
if grep -q "$DISK_UUID" /etc/fstab; then
echo -e "\033[33m警告:fstab中已存在该硬盘(UUID:$DISK_UUID)的配置,将覆盖原有配置\033[0m"
# 删除原有配置
sed -i "/$DISK_UUID/d" /etc/fstab
fi
# 写入fstab配置(UUID方式,最稳定)
cat >> /etc/fstab << EOF
# 自动挂载 $DISK_DEV 到 $MOUNT_DIR
UUID=$DISK_UUID $MOUNT_DIR $FS_TYPE defaults 0 0
EOF
# 验证fstab配置是否正确(避免语法错误导致开机失败)
mount -a || {
echo -e "\033[31m错误:fstab配置有误,已自动恢复备份\033[0m"
cp "$FSTAB_BACKUP" /etc/fstab
exit 1
}
##############################################################################
# 操作完成,输出结果
##############################################################################
echo -e "\033[32m=======================================\033[0m"
echo -e "\033[32m 硬盘挂载操作完成! \033[0m"
echo -e "\033[32m=======================================\033[0m"
echo -e "硬盘设备:$DISK_DEV"
echo -e "挂载目录:$MOUNT_DIR"
echo -e "文件系统:$FS_TYPE"
echo -e "硬盘UUID:$DISK_UUID"
echo -e "开机自启:已配置(fstab)"
echo -e "\033[34m验证命令:df -h | grep $MOUNT_DIR\033[0m"
echo -e "\033[34m卸载命令:umount $MOUNT_DIR\033[0m"
echo -e "\033[32m=======================================\033[0m"