├── .gitignore ├── LICENSE ├── README.md ├── config.sh ├── dbMonitor.sh ├── fileMonitor.sh ├── main.sh ├── notice.sh └── sysMonitor.sh /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2017 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # shellMonitor 2 | 一个 Linux 下基于 bash 的文件和数据库监控及备份工具。 3 | 4 | 写这个工具的原因,在于一个朋友的一个小电商网站,因为未明原因被黑了,总是会被增加超级管理员,并将收款账号改成别人的。于是有了写一个监控工具的想法。 5 | 6 | > 因为不断的重新安装/初始化各项系统服务,为了方(TOU)便(LAN),写了一个[服务器初始化脚本](https://github.com/zsenliao/initServer),主要功能包括: 7 | > * 可选添加用户及 SSH 傻瓜式配置; 8 | > * git/zsh/oh-my-zsh 等安装、vim 升级(增加`nginx`, `ini`, `php`, `python`等文件类型的高亮显示); 9 | > * MySQL/PHP/Python3(uwsgi)/Redis/Nodejs/Nginx/ikev2/acme.sh 等服务可选择安装; 10 | > * 提供了一个简单的管理工具,用于管理`nginx`,`mysql`,`php-fpm`,`redis`,`uwsgi`等服务,以及新增站点(自动申请并配置安装域名证书); 11 | 12 | ## 主要功能 13 | 14 | ### 监控功能 15 | * 文件监控:主要监控网站文件,可以监控多个网站目录,也可以在配置中将 `Nginx`、`PHP`、`MySQL` 等的配置文件也添加到监控中; 16 | * 数据库监控:可以监控指定数据库中的指定数据表;也可以对指定的表指定字段做监控; 17 | * 数据库备份:设定的数据库全量傻瓜式备份,无监控功能; 18 | 19 | ### 报警功能 20 | * Server酱:通过「[Server酱](http://sc.ftqq.com/3.version)」推送预警消息通知(只能推送给**单个**微信账号); 21 | * PushBear:通过「[PushBear](https://pushbear.ftqq.com/admin/#/)」推送预警消息通知(可以推送给**多个**微信账号); 22 | * 微信报警:设置好相关的微信公众号参数后,监控到改变会发送微信模板通知(可以推送给**多个**微信账号); 23 | * 邮件通知:详细的改变内容会通过邮件发送; 24 | > 提示:如果是阿里云或者腾讯云服务器,会禁止 `25` 端口,默认方式邮件发送失败。可以手动配置邮件发送服务器或者 `MUTT` ,设置以 `SMTP` 的方式发送邮件。也可以在云服务商管理后台申请解封 `25` 端口。 25 | 26 | #### 关于Server酱通知 27 | 微信接收通知其实是相当方便的一种方式,但测试账号发出的通知会被折叠到订阅号中,一不留神可能就错过通知消息。 28 | 29 | 而认证又是相当麻烦的一件事情:需要企业身份申请服务号认证。所以增加Server酱通知。 30 | 31 | > **说明:** 32 | > * 在[微信推送](http://sc.ftqq.com/?c=wechat&a=bind)中绑定微信号后,就可以在微信对话界面看到推送的消息; 33 | > * Server酱只支持推送到一个微信号,如果想要推送到多个微信号,请使用`PushBear`或微信通知功能; 34 | 35 | #### 关于 PushBear 通知 36 | 与`Server酱`一样,区别在于可以推送到多个微信账号。请点击[这里](https://pushbear.ftqq.com/admin/#/channel)先行设置好通道。 37 | 38 | #### 关于微信通知 39 | 如果没有微信公众号、或者没有做认证的公众号,发送模版消息有限制。可以申请[微信公众平台接口测试账号](https://mp.weixin.qq.com/debug/cgi-bin/sandbox?t=sandbox/login),然后新增测试模版,标题随便写,内容如下: 40 | 41 | > {{first.DATA}} 42 | > 网站名称:{{keyword1.DATA}} 43 | > 监控项目:{{keyword2.DATA}} 44 | > 预警状态:{{keyword3.DATA}} 45 | > {{remark.DATA}} 46 | 47 | ## 使用方式 48 | 49 | * 克隆项目 50 | ```bash 51 | git clone https://github.com/zsenliao/shellMonitor.git 52 | ``` 53 | 54 | * 设置权限 55 | ```bash 56 | chown -R root:root shellMonitor # 建议在 root 权限下操作 57 | chmod +x shellMonitor/*.sh # 添加执行权限 58 | ``` 59 | 60 | * 修改配置 61 | ```bash 62 | vi shellMonitor/config.sh # 根据提示修改相关的配置 63 | ``` 64 | 65 | * 初始化 66 | ```bash 67 | shellMonitor/main.sh init 68 | ``` 69 | 70 | * 检查系统定时任务是否生效 71 | ```bash 72 | crontab -l | grep shellMonitor # shellMonitor 为程序目录名 73 | ``` 74 | 如返回结果为空,请通过`crontab -e`的方式手动添加。 75 | 76 | * `SSH` 登录预警通知的手动添加方式 77 | ```bash 78 | ln -sf /home/shellMonitor/sysMonitor.sh /etc/profile.d/sysMonitor.sh 79 | 80 | sed -i "s/^PrintMotd [a-z]*/#&/g; 1,/#PrintMotd[a-z]*/{s/^#PrintMotd [a-z]*/PrintMotd no/g}" /etc/ssh/sshd_config 81 | 82 | # 重启 SSH 服务 83 | service sshd restart 84 | ``` 85 | > 注意:需要修改 `sysMonitor.sh` 文件中的 `CUR_DIR` 为脚本所在的实际路径 86 | 87 | ## 更新说明 88 | > 如果已经在服务器上使用了本工具,可参照以下说明进行升级 89 | * 下载`除 config.sh 外`的所有文件,覆盖原来的文件 90 | * 修改 `config.sh` 文件内容: 91 | * 所有变量名(如`Mail_Type`、`DB_User`等)全部改为大写字母 92 | * 更改变量值类型: 93 | * `DB_MONITOR_TABLE`: 由字符串改为数组形式 94 | * 增加变量: 95 | * `DB_MONITOR_FIELD`: 数据表中指定监控的字段 96 | * `ENABLE_FILE_MONITOR`: 是否启用文件监控 97 | * `ENABLE_DB_MONITOR`: 是否启用数据库监控,如禁用,数据库备份也会禁用 98 | * 部分变量名更改: 99 | * `WEBSITE` → `HOST_NAME` 100 | * `TOUSER` → `TO_USER` 101 | * `APPID` → `APP_ID` 102 | * `SECRET` → `APP_SECRET` 103 | * `SCKEY` → `FTQQ_SCKEY` 104 | * `SENDKEY` → `FTQQ_SENDKEY` 105 | * `SC_NOTIC` → `FTQQ_SC_NOTICE` 106 | * `PUSHBEAR_NOTIC` → `FTQQ_PB_NOTICE` 107 | * 删除变量(可选): 108 | * `MAIL_FROM` 109 | * `DB_ADMIN_MONITOR_TABLE` 110 | * `DB_ADMIN_MONITOR_FIELD` 111 | * 在当前目录下执行以下操作: 112 | * sed -i "s#\\\`which mysql\\\`#\`which mysql\`#g" dbMonitor.sh 113 | * sed -i "s#\\\`which mysqldump\\\`#\`which mysqldump\`#g" dbMonitor.sh 114 | 115 | ## TODO 116 | * [x] 将设定系统任务添加到初始化任务中 117 | * [x] 监控文件或数据库设置错误情况下的 ~~异常~~ **报警** 处理 118 | * [x] 如邮件通知方式选择 `mutt` 但系统中并没有安装改工具下的处理 119 | * [x] 增加 `SSH` 登录的预警通知 120 | * [x] 增加 `SFTP` 登录的预警通知 121 | * [ ] 增加 `SCP` 上传文件的预警通知 122 | * [x] 增加「[PushBear](http://pushbear.ftqq.com/admin/#/api)」预警通知功能 123 | * [x] 增加 「[Server酱](http://sc.ftqq.com/3.version)」预警通知功能 124 | * [x] 优化微信 `ACCESS_TOKEN` 获取方式 125 | * [x] ~~文件监控中,增加多个排除的目录~~ 126 | * [x] 优化数据库/表的监控 127 | * [ ] 检测更改文件的内容 128 | 129 | ## 相关说明及风险提示 130 | * 本工具可作为一些个人网站,或一些小微电商类型网站做**伪**入侵检测工具用,毕竟小微团队在系统运维及安全方面的投入几乎没有; 131 | * 对于具备资源的团队,还是需要从**运维策略**上来考虑安全风险防范的问题; 132 | * 本工具对于系统资源的消耗,并未经测试过;不过我认为目前一般商用的服务器配置,即便是小团队的电商网站的服务器配置,都经得起这点消耗吧; 133 | * 如果您使用了本工具,也请不要完全依赖本工具。如有条件,想办法做系统层面、数据库层面、代码层面的加固;如条件实在不足,也请多关注您系统的异常状况。 134 | -------------------------------------------------------------------------------- /config.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | ### 配制开始,根据需要修改以下值 ### 4 | # 注意:变量值 前\后 不能有空格 5 | 6 | # 基础设置 7 | HOST_NAME="myServer" # 服务器 8 | BACKUP_DIR="/data/backup" # 备份文件保存目录 9 | BACKUP_DAY="30" # 保留备份文件的天数 10 | DB_BACK_PER="D" # 数据库备份周期 D/每天 H/每小时 11 | MIN_SIZE="100" # 保留最少容量 M。存储空间低于该容量不再备份,并发送预警通知 12 | DIFF_TYPE="du -b" # 文件比较方式。可选:du -b 文件大小对比; md5sum md5方式 13 | 14 | # 文件监控设置 15 | MONITOR_DIR="/data/wwwroot /data/wwwconf" # 监控目录,多个目录用空格隔开 16 | EXCLUDE_DIR="/data/wwwlogs" # 排除目录,多个目录用空格隔开 17 | 18 | ENABLE_FILE_MONITOR="true" # 是否启用文件监控 19 | ENABLE_DB_MONITOR="true" # 是否启用数据库监控,如禁用,数据库备份也会禁用 20 | 21 | # 备份相关,如不启用,请改为 false 22 | ZIP_BACKUP="true" # 启用 ZIP 压缩备份 23 | FILE_BACKUP="true" # 启用文件备份 24 | 25 | # 通知相关,如不启用,请改为 false 26 | MAIL_NOTICE="true" # 邮件通知 27 | WECHAT_NOTICE="true" # 微信通知 28 | FTQQ_SC_NOTICE="false" # Server酱通知 29 | FTQQ_PB_NOTICE="false" # PushBear通知 30 | 31 | # 发邮件参数,如果 MAIL_NOTICE 值为 true,以下内容必填 32 | MAIL_TO="" # 接受报警通知邮箱,多个邮箱请用空格隔开 33 | MAIL_TYPE="mail" # 发送邮件方式,可选 mail 或 mutt 34 | 35 | # 微信推送参数,如果 WECHAT_NOTICE 值为 true,以下内容必填 36 | TO_USER="" # 接收推送用户 openid,多个用户用空格隔开 37 | TEMPLATE_ID="" # 模版ID 38 | APP_ID="" 39 | APP_SECRET="" 40 | 41 | FTQQ_SCKEY="" # Server酱的 KEY 42 | FTQQ_SENDKEY="" # PushBear 的 SendKey 43 | 44 | # 数据库配置 45 | # 备份数据库设置:按周期、全量备份,不做对比及报警 46 | DB_HOST="localhost" 47 | DB_USER="root" 48 | DB_PASS="root" 49 | DB_NAME="all" # 需要备份的数据库名 All 或 输入类似 db1 db2 的列表清单 50 | CREATE_DATABASE="true" # 备份MYSQL时生成CREATE数据库语句 51 | # 数据库监控设置:定时执行,如数据有改动,会发送报警通知 52 | DB_MONITOR_NAME="db1 db2" # 需要监控的数据库名,多个数据库以空格隔开 53 | DB_MONITOR_TABLE=("db1_tb1 db1_tb2 db1_tb3" "db2_tb1 db2_tb2") # 数据库中需要监控的表,多个表以空格隔开。表位置需(引号间的空格)对应上面的数据库位置 54 | DB_MONITOR_FIELD=("\* db1_tb2_fd1,db1_tb2_fd2,db1_tb2_fd3 \*" "db2_tb1_fd1,db2_tb1_fd2 \*") # 监控数据表中,指定监控的字段。字段之间不能有空格,如不指定请输入 \* (注意:需要反斜杠) 55 | 56 | ### 配制结束 ### 57 | -------------------------------------------------------------------------------- /dbMonitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 数据库备份及指定数据表监控 4 | # 数据库备份按设定周期执行,如果有则跳过,没有则执行备份 5 | # 数据表监控与文件监控同频次 6 | dbMonitor() { 7 | if ! cat /etc/my.cnf | grep ^user 1>/dev/null && ! cat /root/.my.cnf | grep ^user 1>/dev/null; then 8 | DB_USER="-u${DB_USER}" 9 | else 10 | DB_USER="" 11 | fi 12 | if ! cat /etc/my.cnf | grep ^password 1>/dev/null && ! cat /root/.my.cnf | grep ^password 1>/dev/null; then 13 | DB_PASS="-p${DB_PASS}" 14 | else 15 | DB_PASS="" 16 | fi 17 | 18 | if [[ ${DB_BACK_PER} == "H" ]]; then 19 | BACKUP_DB_FILE="${BACKUP_DB_DIR}/db.$(date +%F_%H).sql.gz" 20 | else 21 | BACKUP_DB_FILE="${BACKUP_DB_DIR}/db.$(date +%F).sql.gz" 22 | fi 23 | if [[ ! -f ${BACKUP_DB_FILE} ]]; then 24 | # 备份数据库 25 | OPT="--quote-names --opt" 26 | # 检查是否需要生成CREATE数据库语句 27 | if [[ "${CREATE_DATABASE}" == "true" ]]; then 28 | OPT="${OPT} --databases" 29 | else 30 | OPT="${OPT} --no-create-db" 31 | fi 32 | 33 | # 检查是否是备份所有数据库 34 | if [[ "${DB_NAME}" == "all" ]]; then 35 | DB_NAME="--all-databases" 36 | else 37 | DB_NAME="--databases ${DB_NAME}" 38 | fi 39 | 40 | if ! `which mysqldump` ${DB_USER} ${DB_PASS} --host=${DB_HOST} ${OPT} ${DB_NAME} | gzip > "${BACKUP_DB_FILE}" 2>/tmp/shellMonitor.sql.error; then 41 | error_msg=$(cat /tmp/shellMonitor.sql.error) 42 | WeChatNotice "数据库备份失败!" "${HOST_NAME}" "数据库备份" "备份失败" "错误信息:${error_msg}" 43 | ServerNotice "${HOST_NAME} 数据库备份失败!" "错误信息:${error_msg}" 44 | MailNotice "${HOST_NAME} 数据库备份失败!" "错误信息:${error_msg}" 45 | fi 46 | # `which mysqldump` --host=${DB_HOST} ${OPT} ${DB_NAME} | gzip > ${BACKUP_DB_FILE} 47 | fi 48 | 49 | # 监控指定的数据表 50 | idx=0 51 | for DB in $(echo "${DB_MONITOR_NAME}" | tr -s ' '); do 52 | FIELD=(`echo ${DB_MONITOR_FIELD[idx]}`) 53 | tdx=0 54 | for TABLE in $(echo "${DB_MONITOR_TABLE[idx]}" | tr -s ' '); do 55 | TMP_DB="/tmp/${DB}.${TABLE}.txt" 56 | ORIGIN_DB="${BACKUP_LOG_DIR}/db.${DB}-${TABLE}.origin.txt" 57 | LOG_DB="${BACKUP_LOG_DIR}/db.${DB}-${TABLE}.${DATE}_change.log" 58 | 59 | if [[ ${FIELD[tdx]} != '*' ]]; then 60 | SQLSTR="select ${FIELD[tdx]} from ${TABLE}" 61 | else 62 | SQLSTR="select * from ${TABLE}" 63 | fi 64 | 65 | if ! `which mysql` ${DB_USER} ${DB_PASS} -D ${DB} -Bse "${SQLSTR}" > "${TMP_DB}" 2>/tmp/shellMonitor.sql.error; then 66 | error_msg=$(cat /tmp/shellMonitor.sql.error) 67 | WeChatNotice "数据库监控失败!" "${HOST_NAME}" "数据库监控" "监控失败" "错误信息:${error_msg}" 68 | ServerNotice "${HOST_NAME} 数据库监控失败!" "错误信息:${error_msg}" 69 | MailNotice "${HOST_NAME} 数据库监控失败!" "错误信息:${error_msg}" 70 | exit 1 71 | fi 72 | 73 | if [[ ${1} == "init" ]]; then 74 | cp -f "${TMP_DB}" "${ORIGIN_DB}" 75 | else 76 | local DIFF_DB 77 | DIFF_DB=$(diff "${ORIGIN_DB}" "${TMP_DB}" | awk '{print $1$2}' | sort -k2n | uniq -c -s3 | sed '/[<>]/!d;s/1 /【增加】/;s/2 > /tmp/db.change.txt 82 | diff "${ORIGIN_DB}" "${TMP_DB}" >> "${LOG_DB}" 83 | cat "${LOG_DB}" >> /tmp/db.change.txt 84 | echo "" >> /tmp/db.change.txt 85 | cp -f "${TMP_DB}" "${ORIGIN_DB}" # 将当前状态覆盖为初始监控状态 86 | 87 | WeChatNotice "警告:数据库被修改!" "${HOST_NAME}" "${DB}" "${TABLE}" "$(echo ${DIFF_DB} | sed -r "s/\s*//g")" 88 | ServerNotice "${HOST_NAME} 数据库修改通知!" "数据库:${DB}表:\n${TABLE} \n修改内容:$(echo ${DIFF_DB} | sed -r "s/\s*//g")" 89 | fi 90 | 91 | let tdx=tdx+1 92 | done 93 | let idx=idx+1 94 | done 95 | 96 | if [[ ${1} == "init" ]]; then 97 | WeChatNotice "监控初始化成功!" "${HOST_NAME}" "数据库监控初始化" "操作成功" "监控数据库:${DB_MONITOR_NAME}\n监控数据表:${DB_MONITOR_TABLE}" 98 | ServerNotice "${HOST_NAME} 监控初始化成功!" "监控数据库:${DB_MONITOR_NAME}\n监控数据表:${DB_MONITOR_TABLE}" 99 | MailNotice "${HOST_NAME} 监控初始化成功!" "监控数据库:${DB_MONITOR_NAME}\n监控数据表:${DB_MONITOR_TABLE}" 100 | fi 101 | } 102 | -------------------------------------------------------------------------------- /fileMonitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 文件备份 4 | fileMonitor() { 5 | for DIR in $(echo "${MONITOR_DIR}" | tr -s ' '); do 6 | if [[ -d ${DIR} ]]; then 7 | DIR_NAME=${DIR##*/} 8 | TMP_FILE="/tmp/${DIR_NAME}.txt" 9 | ORIGIN_FILE="${BACKUP_LOG_DIR}/${DIR_NAME}.origin.txt" 10 | LOG_FILE="${BACKUP_LOG_DIR}/${DIR_NAME}.${DATE}_change.log" 11 | 12 | getFileInfo "${DIR}" "${TMP_FILE}" 13 | 14 | if [[ ${1} == "init" ]]; then 15 | backupFile "${DIR}" 16 | else 17 | local DIFF_FILE 18 | DIFF_FILE=$(diff "${ORIGIN_FILE}" "${TMP_FILE}" | awk '{print $1$3}' | sort -k2n | uniq -c -s3 | sed '/[<>]/!d;s/1 /【增加】/;s/2 > /tmp/file.change.txt 23 | echo "${DIFF_FILE}" >> "${LOG_FILE}" 24 | echo "${DIFF_FILE}" >> /tmp/file.change.txt 25 | echo "" >> /tmp/file.change.txt 26 | cp -f "${TMP_FILE}" "${ORIGIN_FILE}" # 将当前状态覆盖为初始监控状态 27 | backupFile "${DIR}" 28 | 29 | WeChatNotice "警告:监控文件被修改!" "${HOST_NAME}" "${DIR_NAME}" "文件更改" "$(echo ${DIFF_FILE} | sed -r "s/\s*//g")" 30 | ServerNotice "监控项目:${DIR_NAME}文件修改" "修改内容:$(echo ${DIFF_FILE} | sed -r "s/\s*//g")" 31 | fi 32 | fi 33 | done 34 | 35 | if [[ ${1} == "init" ]]; then 36 | WeChatNotice "监控初始化成功!" "${HOST_NAME}" "文件监控初始化" "操作成功" "监控目录:${MONITOR_DIR}\n排除目录:${EXCLUDE_DIR}" 37 | ServerNotice "${HOST_NAME} 监控初始化成功!" "监控目录:${MONITOR_DIR}\n排除目录:${EXCLUDE_DIR}" 38 | MailNotice "${HOST_NAME} 监控初始化成功!" "监控目录:${MONITOR_DIR}\n排除目录:${EXCLUDE_DIR}" 39 | fi 40 | } 41 | 42 | getFileInfo() { 43 | # 遍历指定目录下的文件大小及路径并重定向到日志文件 44 | # find: 需要验证目录存在 45 | if [[ -n ${EXCLUDE_DIR} ]]; then 46 | # 排除目录 47 | find "${1}" \( -path $(echo ${EXCLUDE_DIR} | sed "s/ / -o -path /") \) -prune -o -type f -print0 2>/tmp/shellMonitor.file.error | xargs -0 $(echo ${DIFF_TYPE}) > "${2}" 48 | else 49 | find "${1}" -type f -print0 2>/tmp/shellMonitor.file.error | xargs -0 $(echo ${DIFF_TYPE}) > "${2}" 50 | fi 51 | 52 | error_msg=$(cat /tmp/shellMonitor.file.error) 53 | if [[ ${error_msg} != "" ]]; then 54 | WeChatNotice "文件监控失败!" "${HOST_NAME}" "文件监控" "监控失败" "错误信息:${error_msg}" 55 | ServerNotice "${HOST_NAME} 文件监控失败!" "错误信息:${error_msg}" 56 | MailNotice "${HOST_NAME} 文件监控失败!" "错误信息:${error_msg}" 57 | exit 1 58 | fi 59 | } 60 | 61 | backupFile() { 62 | if [[ ${ZIP_BACKUP} = "true" ]]; then 63 | tar -zcPf "${BACKUP_TAR_DIR}/${DIR_NAME}.${DATE}.tar.gz" "${1}" # 备份文件 64 | fi 65 | 66 | if [[ ${FILE_BACKUP} = "true" ]]; then 67 | cp -rf "${1}" "${BACKUP_FILE_DIR}/${DIR_NAME}_${DATE}" # 备份文件 68 | fi 69 | } 70 | -------------------------------------------------------------------------------- /main.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | CUR_DIR=$(cd $(dirname $BASH_SOURCE); pwd) 4 | 5 | . ${CUR_DIR}/config.sh 6 | . ${CUR_DIR}/fileMonitor.sh 7 | . ${CUR_DIR}/dbMonitor.sh 8 | . ${CUR_DIR}/notice.sh 9 | 10 | # 当前剩余容量小于设定容量,预警并退出备份 11 | CUR_SIZE=$(df -m /home | awk 'END{print $4}') 12 | if [[ ${CUR_SIZE} -lt ${MIN_SIZE} ]]; then 13 | MailNotice "警告:服务器剩余空间不足!" "剩余 ${CUR_SIZE}M" 14 | WeChatNotice "警告:服务器剩余空间不足!" "服务器空间" "剩余 ${CUR_SIZE}M" "备份失败" 15 | exit 0 16 | fi 17 | 18 | # 日期变量 19 | DATE=`date +%F_%H%M` 20 | DEL_DATE=`date -d -${BACKUP_DAY}day +%F` 21 | 22 | # 备份目录 23 | BACKUP_TAR_DIR="${BACKUP_DIR}/tar" # 压缩文件目录 24 | BACKUP_LOG_DIR="${BACKUP_DIR}/log" # 日志文件目录 25 | BACKUP_FILE_DIR="${BACKUP_DIR}/www" # 文件备份目录 26 | BACKUP_DB_DIR="${BACKUP_DIR}/db" # 数据库备份目录 27 | 28 | 29 | if [[ ${1} = "init" ]]; then 30 | if crontab -l | grep "${CUR_DIR}/main.sh" 1>/dev/null; then 31 | echo "似乎已安装过 shellMonitor, 是否重新安装?" 32 | read -r -p "是(Y)/否(N): " REINSMONITOR 33 | if [[ ${REINSMONITOR} == "y" || ${REINSMONITOR} == "Y" ]]; then 34 | sed -i '/shellMonitor/d' /var/spool/cron/root 35 | else 36 | echo "退出安装 shellMonitor!" 37 | exit 0 38 | fi 39 | fi 40 | 41 | echo -e "\e[0;33m监控周期(默认: 5分钟)\e[0m" 42 | read -r -p "请输入数字: " MONITOR_TIME 43 | MONITOR_TIME=$(echo ${MONITOR_TIME} | sed -r "s/^[ \t]*|[ \t]*$//g") # 删除前后空格 sed -e "s/[ \t]*$//" -e "s/^[ \t]*// 44 | if [[ ${MONITOR_TIME} == "" ]]; then 45 | MONITOR_TIME=5 46 | fi 47 | 48 | echo -e "\e[0;33m请选择配置文件设置方式(默认按提示操作)\e[0m" 49 | read -r -p "按提示操作(1)/手动编辑(2): " EDITTYPE 50 | if [[ ${EDITTYPE} == 2 ]]; then 51 | echo -e "\e[0;32m已选择手动编辑配置文件。\e[0m" 52 | echo -e "\e[0;31m脚本不会检查相关配置值,请确保配置文件 config.sh 已经设定好!\e[0m" 53 | read -r -p "已设置好(Y)/还未设置(N): " GOINSTALL 54 | if [[ ${GOINSTALL} == "n" || ${GOINSTALL} == "N" ]]; then 55 | echo -e "\e[0;32m退出安装。\e[0m" 56 | exit 0 57 | fi 58 | else 59 | if [ -z "${HOST_NAME}" ]; then 60 | DEFHOSTNAME=$(cat /etc/hostname) 61 | echo -e "\e[0;33m服务器名称(默认: ${DEFHOSTNAME})\e[0m" 62 | read -r -p "请输入(可直接回车): " HOST_NAME 63 | if [ -z "${HOST_NAME}" ]; then 64 | HOST_NAME=${DEFHOSTNAME} 65 | fi 66 | fi 67 | sed -i "s#HOST_NAME=\".*\"#HOST_NAME=\"${HOST_NAME}\"#g" "${CUR_DIR}/config.sh" 68 | 69 | echo -e "\e[0;33m备份文件保存目录(默认: ${INSHOME}/backups)\e[0m" 70 | read -r -p "请输入: " BACKUP_DIR 71 | BACKUP_DIR=$(echo ${BACKUP_DIR} | sed -r "s/^[ \t]*|[ \t]*$//g") 72 | if [ -z "${BACKUP_DIR}" ]; then 73 | BACKUP_DIR="${INSHOME}/backups" 74 | fi 75 | sed -i "s#BACKUP_DIR=\".*\"#BACKUP_DIR=\"${BACKUP_DIR}\"#g" "${CUR_DIR}/config.sh" 76 | 77 | echo -e "\e[0;33m保留备份文件的天数(默认: 30)\e[0m" 78 | read -r -p "请输入数字: " BACKUP_DAY 79 | BACKUP_DAY=$(echo ${BACKUP_DAY} | sed -r "s/^[ \t]*|[ \t]*$//g") 80 | if [ -z "${BACKUP_DAY}" ]; then 81 | BACKUP_DAY=30 82 | fi 83 | sed -i "s#BACKUP_DAY=\".*\"#BACKUP_DAY=\"${BACKUP_DAY}\"#g" "${CUR_DIR}/config.sh" 84 | 85 | echo -e "\e[0;33m最低存储容量(存储空间低于该值将不再执行备份。默认: 100)\e[0m" 86 | read -r -p "请输入数字: " MIN_SIZE 87 | MIN_SIZE=$(echo ${MIN_SIZE} | sed -r "s/^[ \t]*|[ \t]*$//g") 88 | if [ -z "${MIN_SIZE}" ]; then 89 | MIN_SIZE=100 90 | fi 91 | sed -i "s#MIN_SIZE=\".*\"#MIN_SIZE=\"${MIN_SIZE}\"#g" "${CUR_DIR}/config.sh" 92 | 93 | echo -e "\e[0;33m是否启用邮件通知(默认: 否)?\e[0m" 94 | read -r -p "是(Y)/否(N): " MAIL_NOTICE 95 | if [[ ${MAIL_NOTICE} == "y" || ${MAIL_NOTICE} == "Y" ]]; then 96 | MAIL_NOTICE="true" 97 | echo -e "\e[0;32m请注意:部分服务器需要设置通过 SMTP 的方式发送邮件!\e[0m" 98 | echo "" 99 | echo -e "\e[0;33m请选择邮件发送方式(默认: mail)?\e[0m" 100 | read -r -p "mail/mutt(请输入小写): " MAIL_TYPE 101 | if [[ ${MAIL_TYPE} == "mutt" ]]; then 102 | MAIL_TYPE="mutt" 103 | yum install -y mutt 104 | else 105 | MAIL_TYPE="mail" 106 | fi 107 | 108 | echo -e "\e[0;33m接收报警通知的邮箱(多个邮箱用空格隔开)\e[0m" 109 | while :;do 110 | read -r -p "请输入: " MAIL_TO 111 | MAIL_TO=$(echo ${MAIL_TO} | sed -r "s/^[ \t]*|[ \t]*$//g") 112 | if [[ ${MAIL_TO} != "" ]]; then 113 | break 114 | else 115 | echo -e "\e[0;31m接收报警邮箱不能为空!\e[0m" 116 | fi 117 | done 118 | else 119 | MAIL_NOTICE="false" 120 | fi 121 | sed -i "s#MAIL_NOTICE=\".*\"#MAIL_NOTICE=\"${MAIL_NOTICE}\"#g" "${CUR_DIR}/config.sh" 122 | sed -i "s#MAIL_TYPE=\".*\"#MAIL_TYPE=\"${MAIL_TYPE}\"#g" "${CUR_DIR}/config.sh" 123 | sed -i "s#MAIL_TO=\".*\"#MAIL_TO=\"${MAIL_TO}\"#g" "${CUR_DIR}/config.sh" 124 | 125 | echo -e "\e[0;33m是否启用微信通知(默认: 否)?\e[0m" 126 | read -r -p "是(Y)/否(N): " WECHAT_NOTICE 127 | if [[ ${WECHAT_NOTICE} == "y" || ${WECHAT_NOTICE} == "Y" ]]; then 128 | WECHAT_NOTICE="true" 129 | 130 | echo -e "\e[0;33m接收通知的用户 OPENID(多个用户用空格隔开)\e[0m" 131 | while :;do 132 | read -r -p "请输入: " TO_USER 133 | TO_USER=$(echo ${TO_USER} | sed -r "s/^[ \t]*|[ \t]*$//g") 134 | if [[ ${TO_USER} != "" ]]; then 135 | break 136 | else 137 | echo -e "\e[0;31m用户 OPENID 不能为空!\e[0m" 138 | fi 139 | done 140 | 141 | echo -e "\e[0;33m微信模版 ID\e[0m" 142 | while :;do 143 | read -r -p "请输入: " TEMPLATE_ID 144 | TEMPLATE_ID=$(echo ${TEMPLATE_ID} | sed -r "s/^[ \t]*|[ \t]*$//g") 145 | if [[ ${TEMPLATE_ID} != "" ]]; then 146 | break 147 | else 148 | echo -e "\e[0;31m微信模版 ID 不能为空!\e[0m" 149 | fi 150 | done 151 | 152 | echo -e "\e[0;33m微信公众号 APPID\e[0m" 153 | while :;do 154 | read -r -p "请输入: " APP_ID 155 | APP_ID=$(echo ${APP_ID} | sed -r "s/^[ \t]*|[ \t]*$//g") 156 | if [[ ${APP_ID} != "" ]]; then 157 | break 158 | else 159 | echo -e "\e[0;31m微信公众号 APPID 不能为空!\e[0m" 160 | fi 161 | done 162 | 163 | echo -e "\e[0;33m微信公众号 APPSECRET\e[0m" 164 | while :;do 165 | read -r -p "请输入: " APP_SECRET 166 | APP_SECRET=$(echo ${APP_SECRET} | sed -r "s/^[ \t]*|[ \t]*$//g") 167 | if [[ ${APP_SECRET} != "" ]]; then 168 | break 169 | else 170 | echo -e "\e[0;31m微信公众号 APPSECRET 不能为空!\e[0m" 171 | fi 172 | done 173 | else 174 | WECHAT_NOTICE="false" 175 | fi 176 | sed -i "s#WECHAT_NOTICE=\".*\"#WECHAT_NOTICE=\"${WECHAT_NOTICE}\"#g" "${CUR_DIR}/config.sh" 177 | sed -i "s#TO_USER=\".*\"#TO_USER=\"${TO_USER}\"#g" "${CUR_DIR}/config.sh" 178 | sed -i "s#TEMPLATE_ID=\".*\"#TEMPLATE_ID=\"${TEMPLATE_ID}\"#g" "${CUR_DIR}/config.sh" 179 | sed -i "s#APP_ID=\".*\"#APP_ID=\"${APP_ID}\"#g" "${CUR_DIR}/config.sh" 180 | sed -i "s#APP_SECRET=\".*\"#APP_SECRET=\"${APP_SECRET}\"#g" "${CUR_DIR}/config.sh" 181 | 182 | echo -e "\e[0;33m是否启用 Server 酱通知(默认: 否)?\e[0m" 183 | read -r -p "是(Y)/否(N): " FTQQ_SC_NOTICE 184 | if [[ ${FTQQ_SC_NOTICE} == "y" || ${FTQQ_SC_NOTICE} == "Y" ]]; then 185 | FTQQ_SC_NOTICE="true" 186 | 187 | echo -e "\e[0;33mServer 酱 KEY\e[0m" 188 | while :;do 189 | read -r -p "请输入: " FTQQ_SCKEY 190 | FTQQ_SCKEY=$(echo ${FTQQ_SCKEY} | sed -r "s/^[ \t]*|[ \t]*$//g") 191 | if [[ ${FTQQ_SCKEY} != "" ]]; then 192 | break 193 | else 194 | echo -e "\e[0;31mServer 酱 KEY 不能为空!\e[0m" 195 | fi 196 | done 197 | else 198 | FTQQ_SC_NOTICE="false" 199 | fi 200 | sed -i "s#FTQQ_SC_NOTICE=\".*\"#FTQQ_SC_NOTICE=\"${FTQQ_SC_NOTICE}\"#g" "${CUR_DIR}/config.sh" 201 | sed -i "s#FTQQ_SCKEY=\".*\"#FTQQ_SCKEY=\"${FTQQ_SCKEY}\"#g" "${CUR_DIR}/config.sh" 202 | 203 | echo -e "\e[0;33m是否启用 PushBear 通知(默认: 否)?\e[0m" 204 | read -r -p "是(Y)/否(N): " FTQQ_PB_NOTICE 205 | if [[ ${FTQQ_PB_NOTICE} == "y" || ${FTQQ_PB_NOTICE} == "Y" ]]; then 206 | FTQQ_PB_NOTICE="true" 207 | 208 | echo -e "\e[0;33mPushBear SendKey\e[0m" 209 | while :;do 210 | read -r -p "请输入: " FTQQ_SENDKEY 211 | FTQQ_SENDKEY=$(echo ${FTQQ_SENDKEY} | sed -r "s/^[ \t]*|[ \t]*$//g") 212 | if [[ ${FTQQ_SENDKEY} != "" ]]; then 213 | break 214 | else 215 | echo -e "\e[0;31mPushBear SendKey 不能为空!\e[0m" 216 | fi 217 | done 218 | else 219 | FTQQ_PB_NOTICE="false" 220 | fi 221 | sed -i "s#FTQQ_PB_NOTICE=\".*\"#FTQQ_PB_NOTICE=\"${FTQQ_PB_NOTICE}\"#g" "${CUR_DIR}/config.sh" 222 | sed -i "s#FTQQ_SENDKEY=\".*\"#FTQQ_SENDKEY=\"${FTQQ_SENDKEY}\"#g" "${CUR_DIR}/config.sh" 223 | 224 | if [[ ${MAIL_NOTICE} == "false" && ${WECHAT_NOTICE} == "false" && ${FTQQ_SC_NOTICE} == "false" && ${FTQQ_PB_NOTICE} == "false" ]]; then 225 | echo "======++++++======" 226 | echo -e "\e[0;31m所有通知方式都已禁用,将无法接收系统的任何警报信息!如要启用,请编辑 config.sh 中对应值。\e[0m" 227 | echo "======++++++======" 228 | fi 229 | 230 | echo -e "\e[0;33m是否启用文件监控(默认: 启用)\e[0m" 231 | read -r -p "启用(Y)/不启用(N): " ENABLE_FILE_MONITOR 232 | if [[ ${ENABLE_FILE_MONITOR} == "n" || ${ENABLE_FILE_MONITOR} == "N" ]]; then 233 | ENABLE_FILE_MONITOR="false" 234 | else 235 | ENABLE_FILE_MONITOR="true" 236 | 237 | echo -e "\e[0;33m请选择数文件比较方式(默认: du)\e[0m" 238 | read -r -p "请输入小写(md5/du): " DIFF_TYPE 239 | if [[ ${DIFF_TYPE} == "md5" || ${DIFF_TYPE} == "MD5" ]]; then 240 | DIFF_TYPE="md5sum" 241 | else 242 | DIFF_TYPE="du -b" 243 | fi 244 | sed -i "s#DIFF_TYPE=\".*\"#DIFF_TYPE=\"${DIFF_TYPE}\"#g" "${CUR_DIR}/config.sh" 245 | 246 | echo -e "\e[0;33m要监控的文件目录(多个目录用空格隔开)\e[0m" 247 | while :;do 248 | read -r -p "请输入: " MONITOR_DIR 249 | MONITOR_DIR=$(echo ${MONITOR_DIR} | sed -r "s/^[ \t]*|[ \t]*$//g") 250 | if [[ ${MONITOR_DIR} != "" ]]; then 251 | break 252 | else 253 | echo -e "\e[0;31m监控目录不能为空!\e[0m" 254 | fi 255 | done 256 | sed -i "s#MONITOR_DIR=\".*\"#MONITOR_DIR=\"${MONITOR_DIR}\"#g" "${CUR_DIR}/config.sh" 257 | 258 | echo -e "\e[0;33m要排除的目录(该目录下的文件不做监控,多个目录用空格隔开) \e[0m" 259 | read -r -p "请输入(不添加直接回车): " EXCLUDE_DIR 260 | EXCLUDE_DIR=$(echo ${EXCLUDE_DIR} | sed -r "s/^[ \t]*|[ \t]*$//g") 261 | sed -i "s#EXCLUDE_DIR=\".*\"#EXCLUDE_DIR=\"${EXCLUDE_DIR}\"#g" "${CUR_DIR}/config.sh" 262 | 263 | echo -e "\e[0;33m是否启用 ZIP 压缩备份文件(默认: 是)?\e[0m" 264 | read -r -p "是(Y)/否(N): " ZIP_BACKUP 265 | if [[ ${ZIP_BACKUP} == "n" || ${ZIP_BACKUP} == "N" ]]; then 266 | ZIP_BACKUP="false" 267 | else 268 | ZIP_BACKUP="true" 269 | fi 270 | sed -i "s#ZIP_BACKUP=\".*\"#ZIP_BACKUP=\"${ZIP_BACKUP}\"#g" "${CUR_DIR}/config.sh" 271 | 272 | echo -e "\e[0;33m是否启用文件复制备份文件(默认: 是)?\e[0m" 273 | read -r -p "是(Y)/否(N): " FILE_BACKUP 274 | if [[ ${FILE_BACKUP} == "n" || ${FILE_BACKUP} == "N" ]]; then 275 | FILE_BACKUP="false" 276 | else 277 | FILE_BACKUP="true" 278 | fi 279 | sed -i "s#FILE_BACKUP=\".*\"#FILE_BACKUP=\"${FILE_BACKUP}\"#g" "${CUR_DIR}/config.sh" 280 | fi 281 | 282 | echo -e "\e[0;33m是否启用数据库监控(默认: 启用)\e[0m" 283 | read -r -p "启用(Y)/不启用(N): " ENABLE_DB_MONITOR 284 | if [[ ${ENABLE_DB_MONITOR} == "n" || ${ENABLE_DB_MONITOR} == "N" ]]; then 285 | ENABLE_DB_MONITOR="false" 286 | else 287 | ENABLE_DB_MONITOR="true" 288 | 289 | if ! cat /etc/my.cnf | grep ^user 1>/dev/null && ! cat /root/.my.cnf | grep ^user 1>/dev/null; then 290 | echo -e "\e[0;33mMySQL 数据库用户名(默认: root)\e[0m" 291 | read -r -p "请输入: " DB_USER 292 | DB_USER=$(echo ${DB_USER} | sed -r "s/^[ \t]*|[ \t]*$//g") 293 | if [ -z "${DB_USER}" ]; then 294 | DB_USER="root" 295 | fi 296 | sed -i "s#DB_USER=\".*\"#DB_USER=\"${DB_USER}\"#g" "${CUR_DIR}/config.sh" 297 | fi 298 | if ! cat /etc/my.cnf | grep ^password 1>/dev/null && ! cat /root/.my.cnf | grep ^password 1>/dev/null; then 299 | echo -e "\e[0;33mMySQL 数据库密码(请注意前后空格)\e[0m" 300 | while :;do 301 | read -r -p "请输入: " DB_PASS 302 | if [[ ${DB_PASS} != "" ]]; then 303 | break 304 | else 305 | echo -e "\e[0;31m数据库密码不能为空!\e[0m" 306 | fi 307 | done 308 | sed -i "s#DB_PASS=\".*\"#DB_PASS=\"${DB_PASS}\"#g" "${CUR_DIR}/config.sh" 309 | fi 310 | 311 | echo -e "\e[0;33m需要备份的数据库名(多个数据库用空格隔开。默认: all)\e[0m" 312 | read -r -p "请输入(全库备份请输入小写 all 或者直接回车): " DB_NAME 313 | DB_NAME=$(echo ${DB_NAME} | sed -r "s/^[ \t]*|[ \t]*$//g") 314 | if [ -z "${DB_NAME}" ]; then 315 | DB_NAME="all" 316 | fi 317 | sed -i "s#DB_NAME=\".*\"#DB_NAME=\"${DB_NAME}\"#g" "${CUR_DIR}/config.sh" 318 | 319 | echo -e "\e[0;33m备份 MYSQL 时生成 CREATE 数据库语句(默认: 是)?\e[0m" 320 | read -r -p "是(Y)/否(N): " CREATE_DATABASE 321 | if [[ ${CREATE_DATABASE} == "n" || ${CREATE_DATABASE} == "N" ]]; then 322 | CREATE_DATABASE="false" 323 | else 324 | CREATE_DATABASE="true" 325 | fi 326 | sed -i "s#CREATE_DATABASE=\".*\"#CREATE_DATABASE=\"${CREATE_DATABASE}\"#g" "${CUR_DIR}/config.sh" 327 | 328 | echo -e "\e[0;33m请选择数据库备份周期(默认: 天)\e[0m" 329 | read -r -p "每天(D)/每小时(H): " DB_BACK_PER 330 | if [[ ${DB_BACK_PER} == "h" || ${DB_BACK_PER} == "H" ]]; then 331 | DB_BACK_PER="H" 332 | else 333 | DB_BACK_PER="D" 334 | fi 335 | sed -i "s#DB_BACK_PER=\".*\"#DB_BACK_PER=\"${DB_BACK_PER}\"#g" "${CUR_DIR}/config.sh" 336 | 337 | echo -e "\e[0;33m需要监控的数据库名(多个数据库用空格隔开)\e[0m" 338 | while :;do 339 | read -r -p "请输入: " DB_MONITOR_NAME 340 | DB_MONITOR_NAME=$(echo ${DB_MONITOR_NAME} | sed -r "s/^[ \t]*|[ \t]*$//g") 341 | if [[ ${DB_MONITOR_NAME} != "" ]]; then 342 | break 343 | else 344 | echo -e "\e[0;31m需要监控的数据库不能为空!\e[0m" 345 | fi 346 | done 347 | 348 | for DB in $(echo "${DB_MONITOR_NAME}" | tr -s ' '); do 349 | DB_TABLE="" 350 | DB_FIELD="" 351 | echo -e "\e[0;33m数据库 ${DB} 中监控的表(多个表用空格隔开)\e[0m" 352 | while :;do 353 | read -r -p "请输入: " TMP_TABLE 354 | TMP_TABLE=$(echo ${TMP_TABLE} | sed -r "s/^[ \t]*|[ \t]*$//g") 355 | if [[ ${TMP_TABLE} != "" ]]; then 356 | break 357 | else 358 | echo -e "\e[0;31m需要监控的表不能为空!\e[0m" 359 | fi 360 | done 361 | 362 | DB_TABLE="${DB_TABLE} ${TMP_TABLE}" 363 | for TABLE in $(echo "${TMP_TABLE}" | tr -s ' '); do 364 | echo -e "\e[0;33m${DB} -> ${TABLE} 中监控的字段(多个字段用英文逗号,隔开。\e[0;31m如果字段名是系统关键词,需要加上 \`!\e[0;33m) \e[0m" 365 | read -r -p "请输入(全部字段可直接回车): " TMP_FIELD 366 | TMP_FIELD=$(echo ${TMP_FIELD} | sed -r "s/^[ \t]*|[ \t]*$//g") 367 | if [[ ${TMP_FIELD} == "" ]]; then 368 | TMP_FIELD="*" 369 | else 370 | TMP_FIELD=$(echo "${TMP_FIELD}" | sed -r "s/ *//g" | sed -r 's/`/\\\\`/g') 371 | fi 372 | DB_FIELD="${DB_FIELD} ${TMP_FIELD}" 373 | done 374 | DBMONITORTABLE="${DBMONITORTABLE} \"${DB_TABLE}\"" 375 | DBMONITORFIELD="${DBMONITORFIELD} \"${DB_FIELD}\"" 376 | done 377 | 378 | DBMONITORTABLE=$(echo ${DBMONITORTABLE} | sed -r "s/ *\" */\\\"/g" | sed -r 's/""/" "/g') 379 | DBMONITORFIELD=$(echo ${DBMONITORFIELD} | sed -r "s/ *\" */\\\"/g" | sed -r 's/""/" "/g') 380 | DB_MONITOR_TABLE=(`echo ${DBMONITORTABLE}`) 381 | DB_MONITOR_FIELD=(`echo ${DBMONITORFIELD}`) 382 | 383 | sed -i "s#DB_MONITOR_NAME=\".*\"#DB_MONITOR_NAME=\"${DB_MONITOR_NAME}\"#g" "${CUR_DIR}/config.sh" 384 | sed -i "s#DB_MONITOR_TABLE=(.*)#DB_MONITOR_TABLE=(${DBMONITORTABLE})#g" "${CUR_DIR}/config.sh" 385 | sed -i "s#DB_MONITOR_FIELD=(.*)#DB_MONITOR_FIELD=(${DBMONITORFIELD})#g" "${CUR_DIR}/config.sh" 386 | fi 387 | fi 388 | 389 | mkdir -p ${BACKUP_DIR}/{tar,log,www,db} 390 | ln -sf ${CUR_DIR}/sysMonitor.sh /etc/profile.d/sysMonitor.sh 391 | sed -i "s/^PrintMotd [a-z]*/#&/g; 1,/#PrintMotd[a-z]*/{s/^#PrintMotd [a-z]*/PrintMotd no/g}" /etc/ssh/sshd_config 392 | service sshd restart 393 | 394 | sed -i "s#\`which mysql\`#`which mysql`#g" "${CUR_DIR}/dbMonitor.sh" 395 | sed -i "s#\`which mysqldump\`#`which mysqldump`#g" "${CUR_DIR}/dbMonitor.sh" 396 | sed -i "s#CUR_DIR=.*#CUR_DIR=${CUR_DIR}#g" "${CUR_DIR}/sysMonitor.sh" 397 | 398 | echo "*/${MONITOR_TIME} * * * * ${CUR_DIR}/main.sh" >> /var/spool/cron/root 399 | fi 400 | 401 | 402 | if [[ ${ENABLE_FILE_MONITOR} == "true" ]]; then 403 | fileMonitor ${1} 404 | fi 405 | if [[ ${ENABLE_DB_MONITOR} == "true" ]]; then 406 | dbMonitor ${1} 407 | fi 408 | 409 | if [[ -f "/tmp/file.change.txt" ]]; then 410 | # 附件作为第三个参数: -a 文件路径 411 | MailNotice "${HOST_NAME} 文件监控预警" "$(cat /tmp/file.change.txt | tr -d '\r')" 412 | rm -f /tmp/file.change.txt 413 | fi 414 | if [[ -f "/tmp/db.change.txt" ]]; then 415 | MailNotice "${HOST_NAME} 数据库监控预警" "$(cat /tmp/db.change.txt | tr -d '\r')" 416 | rm -f /tmp/db.change.txt 417 | fi 418 | 419 | if [[ ${BACKUP_DAY} != 0 ]]; then 420 | rm -f "${BACKUP_TAR_DIR}/*.${DEL_DATE}*.tar.gz" 421 | rm -rf "${BACKUP_FILE_DIR}/*.${DEL_DATE}*" 422 | rm -f "${BACKUP_DB_DIR}/db.${DEL_DATE}*.sql.gz" 423 | fi 424 | -------------------------------------------------------------------------------- /notice.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | MailNotice() { 4 | # 将备份文件保存至指定邮箱 5 | if [[ ${MAIL_NOTICE} == "true" ]]; then 6 | if [[ "${MAIL_TYPE}" == "mail" ]]; then 7 | echo "${2}" | mail -s "${1}" "${MAIL_TO}" 8 | fi 9 | 10 | if [[ "${MAIL_TYPE}" == "mutt" ]]; then 11 | for MAILTO in $(echo "${MAIL_TO}" | tr -s ' '); do 12 | echo "${2}" | mutt -s "${1}" "${MAILTO}" 13 | done 14 | fi 15 | fi 16 | } 17 | 18 | WeChatNotice() { 19 | if [[ ${WECHAT_NOTICE} == "true" ]]; then 20 | GetAccessToken 21 | 22 | # 发送模版消息,多个用户以空格分隔 23 | for OPENID in $(echo "${TO_USER}" | tr -s ' '); do 24 | wxTemplate "${OPENID}" "${1}" "${2}" "${3}" "${4}" "${5}" 25 | done 26 | fi 27 | } 28 | 29 | wxTemplate() { 30 | # 发送模版消息 31 | # {{first.DATA}} 32 | # 网站名称:{{keyword1.DATA}} 33 | # 监控项目:{{keyword2.DATA}} 34 | # 预警状态:{{keyword3.DATA}} 35 | # {{remark.DATA}} 36 | curl -s -o /dev/null --request POST \ 37 | --url "https://api.weixin.qq.com/cgi-bin/message/template/send?access_token=${ACCESS_TOKEN}" \ 38 | --header "cache-control: no-cache" \ 39 | --header "content-type: application/json" \ 40 | --data '{ 41 | "touser":"'"${1}"'", 42 | "template_id":"'"${TEMPLATE_ID}"'", 43 | "url":"", 44 | "data":{ 45 | "first": { 46 | "value":"'"${2}"'\n", 47 | "color":"#565656" 48 | }, 49 | "keyword1": { 50 | "value":"'"${3}"'", 51 | "color":"#173177" 52 | }, 53 | "keyword2": { 54 | "value":"'"${4}"'", 55 | "color":"#ff7700" 56 | }, 57 | "keyword3": { 58 | "value":"'"${5}"'", 59 | "color":"#173177" 60 | }, 61 | "remark": { 62 | "value":"\n\n'"${6}"'", 63 | "color":"#ff7700" 64 | } 65 | } 66 | }' 67 | } 68 | 69 | GetAccessToken() { 70 | if [ ! -f "/tmp/access_token" ]; then 71 | touch "/tmp/access_token" 72 | GetAccessToken4Curl 73 | else 74 | local MTIME 75 | MTIME=$(cat /tmp/access_token | grep expires_time | cut -d "|" -f 1) 76 | let EXPTIME=$(date +%s)-${MTIME} 77 | if [ ${EXPTIME} -lt 6000 ]; then 78 | ACCESS_TOKEN=$(cat /tmp/access_token | grep access_token | cut -d "|" -f 1) 79 | else 80 | GetAccessToken4Curl 81 | fi 82 | fi 83 | } 84 | 85 | GetAccessToken4Curl() { 86 | # 获取微信 access token 87 | # return: {"access_token":"ACCESS_TOKEN","expires_in":7200} 88 | local JSON_STR 89 | JSON_STR=$(curl -s --request GET --url "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=${APP_ID}&secret=${APP_SECRET}" --header 'cache-control: no-cache') 90 | ACCESS_TOKEN=$(echo "${JSON_STR}" | sed "s/{\"access_token\":\"//" | sed "s/\",\"expires_in\":7200}//") 91 | # ACCESS_TOKEN=${JSON_STR#\{\"access_token\":\"} 92 | # ACCESS_TOKEN=${ACCESS_TOKEN%\",\"expires_in\":7200\}} 93 | 94 | echo "${ACCESS_TOKEN}|access_token" > /tmp/access_token 95 | echo "$(date +%s)|expires_time" >> /tmp/access_token 96 | } 97 | 98 | ServerNotice() { 99 | if [[ ${FTQQ_SC_NOTICE} == "true" ]]; then 100 | curl -s -o /dev/null --request GET \ 101 | --url "https://sc.ftqq.com/${FTQQ_SCKEY}.send?text=${1}&desp=${2}" \ 102 | --header 'cache-control: no-cache' 103 | fi 104 | 105 | if [[ ${FTQQ_PB_NOTICE} == "true" ]]; then 106 | curl -s -o /dev/null --request GET \ 107 | --url "https://pushbear.ftqq.com/sub?sendkey=${FTQQ_SENDKEY}&text=${1}&desp=${2}" \ 108 | --header 'cache-control: no-cache' 109 | fi 110 | } -------------------------------------------------------------------------------- /sysMonitor.sh: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 需改为脚本所在的绝对路径 4 | CUR_DIR=/home/shellMonitor 5 | 6 | . ${CUR_DIR}/config.sh 7 | . ${CUR_DIR}/notice.sh 8 | 9 | LOGIN_IP=`echo $SSH_CLIENT | cut -d " " -f 1` 10 | LOGIN_USER=`whoami` 11 | 12 | WeChatNotice "${HOST_NAME} SSH 登录提醒!" "${HOST_NAME}" "[登录用户]${LOGIN_USER}" "[登录IP]${LOGIN_IP}" "如非本人登录,请检查服务器安全!" 13 | ServerNotice "${HOST_NAME} SSH 登录提醒!" "[登录用户]${LOGIN_USER} \n[登录IP]${LOGIN_IP} \n如非本人登录,请检查服务器安全!" 14 | MailNotice "${HOST_NAME} SSH 登录提醒!" "[登录用户]${LOGIN_USER} \n[登录IP]${LOGIN_IP} \n如非本人登录,请检查服务器安全!" 15 | 16 | # cat /var/log/audit/audit.log | grep "failed" 17 | 18 | # cat /var/log/secure | grep "Failed password" 19 | 20 | lastlog 21 | --------------------------------------------------------------------------------