
运维免费学习网站:https://www.qiuyl.com
声明
1)由于公众号发文不允许文章超链接有外链,所以很多时候需要外部超链接时,只好帖上域名的完整地址。
2)文中所使用的阿里云服务,均可在阿里云控制台的导航栏中的搜索按钮里进行搜索。如:ECS、域名、SSL,直接搜索即可。
3)尽管文章已被我阅读与修改多次,仍无法保证100%正确,如有发现错误望谅解和指正,谢谢!我会在第一时间修改,如有必要会在对应文章的评论区说明。

这是一篇非常系统的内容,帮助你完成一个属于自己的网站和博客系统。以及解答你诸多问题,如:博客的作用?如何部署?SEO优化?等内容。
该系列内容耗费了非常多时间精力,内容共 9 篇。该系列内容介绍,请查看这篇:专栏介绍 如何搞定博客 | 全流程实践指南
起初这是这个系列内容是付费内容,随后我将其公开在了我的免费知识星球知识库,现在我将这篇内容免费公开到公众号。希望大家能有所收获,如果有帮助希望你不要忘记你的双击屏幕点赞👍、转发、收藏,一键三连。
学习企业级运维项目,请关注真成运维导航
你好,我是真成。在上一篇中我们介绍了文章的发布流程,这个时候我们博客系统已经可以进行日常使用了。但为了保障我们博客系统持续的更稳定的对外提供服务,我们要为数据安全、服务器安全、图床安全进行考虑。避免造成一些不必要的损失,如:中勒索病毒、暴力破解服务器密码、盗刷图片流量等,所以数据安全尤为重要。
本篇将介绍对我们的数据库和 WordPress 项目源数据进行备份,同时对服务器端口限制以及图床的防盗链配置。
数据备份
为了使文章结构和阅读更加清晰,首先先介绍一下我们数据备份的整体流程是:
-
数据打包:通过编写 Shell 脚本将数据库和 WordPress 项目源数据打包到本地。 -
数据推送:通过编写 Python 脚本将其数据包上传到 OSS 对象存储中做持久化保存。 -
同时创建定时任务执行以上脚本完成上述任务。
PS:因为我们只有一台服务器,如果只将数据备份到本地意义不大,所以这里会通过 Python 脚本将数据包上传到 OSS 对象存储中保存。
数据打包
数据打包部分,我们将编写一个 Shell 脚本来实现将博客系统数据库和 WordPress 项目源数据进行打包并保存在本地目录中。
1)脚本逻辑说明
-
导出 WordPress 数据库与打包 WorePress 项目源数据。 -
整体打包上述两个数据,为一个压缩文件。
2)脚本运行说明
-
修改配置参数中的变量。 -
source 命令执行脚本即可。
注意:执行备份脚本时,这里必须采用 source 命令执行,因为需要通过该脚本中的变量传递变量到**.oss_env**文件中。
3)创建脚本文件
注意:这里最好通过 vi 或 vim 编辑器手动复制进去,避免脚本中的变量值进行不正确的赋值。
Shell 脚本执行的日志存放目录/var/log/wordpress_db_backup.log。
$ mkdir -p /opt/module/wordpress/script
$ vi /opt/module/wordpress/script/wordpress_db_data_backup.sh
#!/bin/bash
# 配置参数(建议通过环境变量设置)
DB_HOST=${DB_HOST:-localhost}
DB_USER=${DB_USER:-root}
DB_PASSWORD=${DB_PASSWORD:-mysql@qiuyl.com}
DB_NAME=${DB_NAME:-qiuyl}
MAX_BACKUPS=${MAX_BACKUPS:-1}
LOG_FILE=${LOG_FILE:-/var/log/wordpress_db_backup.log}
# WrodPress数据目录
WORDPRESS_DATA_DIR=${WORDPRESS_DATA_DIR:-/opt/module/wordpress/wordpress_data}
# mysql、wordpress备份数据保存目录
BACKUP_DIR=${BACKUP_DIR:-/opt/wordpress_backup}
# mysql、wordpress备份数据通过tar压缩后保存目录
TAR_WORDPRESS_DATA_DIR=${TAR_WORDPRESS_DATA_DIR:-/opt/wordpress_backup_data}
# 日志函数
log() {
echo "[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a $LOG_FILE
}
LOCAL_PWD=<span class="hljs-built_in" style="color: #e6c07b; line-height: 26px;">pwd</span>
# 创建备份目录
mkdir -p $BACKUP_DIR
# 清空目录
rm -rf $BACKUP_DIR/*
# 生成备份文件名
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BACKUP_FILE="${BACKUP_DIR}/mysql-${DB_NAME}-${TIMESTAMP}.sql.gz"
echo $BACKUP_FILE
# 1.执行备份命令
log "Starting MySQL backup..."
docker exec mysql-5.7 mysqldump -h $DB_HOST -u $DB_USER -p$DB_PASSWORD --single-transaction $DB_NAME | gzip > $BACKUP_FILE
# docker exec mysql-5.7 mysqldump -h 127.0.0.1 -u root -p'mysql@qiuyl.com' --single-transaction qiuyl | gzip > qiuyl-test.sql.gz
# 检查备份结果
if [ $? -eq 0 ]; then
log "1.DB_Backup succeeded: $BACKUP_FILE"
else
log "DB_Backup failed!"
exit 1
fi
# 清理db旧备份
#log "Cleaning up old db_backups..."
#BACKUPS=$(ls -t $DB_BACKUP_DIR/*.sql.gz 2>/dev/null)
#COUNT=$(echo "$BACKUPS" | wc -w)
#
#while [ $COUNT -gt $MAX_BACKUPS ]; do
# OLDEST=$(echo "$BACKUPS" | tail -1)
# log "Deleting old backup: $OLDEST"
# rm -f "$OLDEST"
# COUNT=$((COUNT - 1))
#done
#
#log "Backup process completed"
echo "-----------------------------------------------------------------------"
# 2.备份WordPress数据文件
WORDPRESS_BACKUP_FILE_NAME="${BACKUP_DIR}/wordpress-${TIMESTAMP}.tar"
cd $WORDPRESS_DATA_DIR
tar -zcf $WORDPRESS_BACKUP_FILE_NAME ./*
log "2.WordPress数据源备份 Succeeded:${WORDPRESS_BACKUP_FILE_NAME}"
# 清理wordpress旧备份
#log "Cleaning up old wordpress_backups..."
#WORDPRESS_BACKUPS=$(ls -t ${WORDPRESS_BACKUP_DIR}/*.tar 2>/dev/null)
#COUNT_WORDPRESS=$(echo "$WORDPRESS_BACKUPS" | wc -w)
#
#while [ $COUNT_WORDPRESS -gt $MAX_BACKUPS ]; do
# OLDEST_WORDPRESS=$(echo "$WORDPRESS_BACKUPS" | tail -1)
# log "Deleting old WordPress backup: $OLDEST_WORDPRESS"
# rm -f "$COUNT_WORDPRESS"
# COUNT_WORDPRESS=$((COUNT_WORDPRESS - 1))
#done
echo "-----------------------------------------------------------------------"
# 3.压缩WordPress数据文件
mkdir -p $TAR_WORDPRESS_DATA_DIR
TAR_WORDPRESS_DATA_NAME="wordpress_data_${TIMESTAMP}.tar"
cd $BACKUP_DIR
tar -zcf $TAR_WORDPRESS_DATA_NAME ./*
mv $TAR_WORDPRESS_DATA_NAME $TAR_WORDPRESS_DATA_DIR
log "3.tar压缩 wordpress data Succeeded:${TAR_WORDPRESS_DATA_DIR}/${TAR_WORDPRESS_DATA_NAME}"
cd $LOCAL_PWD
# 4.用于.oss_env文件获取的变量
export MYSQL_BACKUP_LOCAL_FILE_PATH="${TAR_WORDPRESS_DATA_DIR}/${TAR_WORDPRESS_DATA_NAME}"
export MYSQL_BACKUP_FILE_NAME=${TAR_WORDPRESS_DATA_NAME}
4)执行方式
unset 命令用于清除环境配置的变量的值。避免因为 source 命令执行脚本后,重新修改变量值时影响变量重新赋值。所以脚本文件中的变量值完成第一次赋值后,再次进行修改后需要执行下列 unset 命令清除变量的值。
echo "$LOCAL_PWD $DB_HOST $DB_USER $DB_PASSWORD $DB_NAME $MAX_BACKUPS $LOG_FILE $WORDPRESS_DATA_DIR $BACKUP_DIR $TAR_WORDPRESS_DATA_DIR $MYSQL_BACKUP_LOCAL_FILE_PATH $MYSQL_BACKUP_FILE_NAME"
unset LOCAL_PWD DB_HOST DB_USER DB_PASSWORD DB_NAME MAX_BACKUPS LOG_FILE WORDPRESS_DATA_DIR BACKUP_DIR TAR_WORDPRESS_DATA_DIR MYSQL_BACKUP_LOCAL_FILE_PATH MYSQL_BACKUP_FILE_NAME
通过 source 命令执行脚本,其他脚本或文件可以引用wordpress_db_data_backup.sh脚本中 export 定义的变量的值。
source /opt/module/wordpress/script/wordpress_db_data_backup.sh
数据推送
数据推送部分,我们将完成下列任务。
-
\1. 创建阿里云 RAM 用户并授予 OSS 上传权限。 -
\2. 安装 Python3.10 环境。 -
\3. 编写 Python 上传到 OSS 的脚本。 -
\4. 创建定时备份上传任务。
创建RAM用户
1)进入 RAM 中创建用户

2)创建AKSK

如果要使其他公网用户可以使用该 AKSK 可开启网络策略。在我们阿里云服务器走内网这个可以不开。


3)创建私有化的 Bucket
这里建议创建一个新的对象存储桶用于存储备份文件,并使用私有化的 Bucket 来存储数据,选择低频访问。同时保障了 Bucket 的安全访问也降低了存储成本。
OSS 存储定价计算查询:https://www.aliyun.com/price/product?spm=a2c4g.11186623.0.0.307d7368KbYQOF#/oss/detail/ossbag

4)RAM 用户授权
这里我们是在 OSS 页面进行用户的权限管理,为了安全只添加 OSS 的上传的权限。操作步骤:在 OSS 页面 -> Bucket -> 权限控制 -> Bucket授权策略 -> 新增授权 -> 选中用户->添加PutObject权限即可。

安装Python3环境
虽然我们云服务器中已经默认安装了 Python-3.6.8,查阅了 OSS 存储的 SDK 开发文档 Python-3.6.8 也是支持的。

但经过测试 Python-3.6.8 版本已经不可用了,版本太低导致无法使用 oss2 依赖。所以这里我们将使用 Python-3.10.10 来运行我们接下来的 Python 程序。
Python 官网下载页面:https://www.python.org/downloads/
1)安装编译环境
使用阿里云 Alibaba Cloud Linux 系统,安装 Python-3.10.10 时只缺少 zlib-devel 包,所以只安装 zlib-devel 包即可。
yum install -y zlib-devel
如果使用的其他 rhel 内核版本系统,使用下面命令安装。
# 其他系统
curl -o /etc/yum.repos.d/CentOS-Base.repo https://mirrors.aliyun.com/repo/Centos-7.repo
# 安装编译所需环境
yum -y install openssl-devel libffi-devel bzip2-devel
yum -y groupinstall "Development Tools"
2)安装Python3.10.10
安装 openssl-1.1 和 Python-3.10.10,安装 Python 3.10 时必须 openssl >= 1.1.1。
mkdir -p /opt/module/openssl && cd /opt/module/openssl
wget https://www.openssl.org/source/openssl-1.1.1q.tar.gz --no-check-certificate
tar zxf openssl-1.1.1q.tar.gz && cd openssl-1.1.1q
./config --prefix=/usr/local/openssl-1.1.1
sudo make && sudo make install
# 安装Python3.10.10
mkdir -p /opt/module/Python && cd /opt/module/Python
wget https://www.python.org/ftp/python/3.10.10/Python-3.10.10.tgz
tar -xf Python-3.10.10.tgz && cd Python-3.10.10
yum install -y zlib-devel
./configure --prefix=/usr/local/python3.10.10 --enable-optimizations --with-openssl=/usr/local/openssl-1.1.1 --with-openssl-rpath=auto
make altinstall
# 添加全局环境变量
cat >> /etc/profile <<EOF
export PYTHON_HOME=/usr/local/python3.10.10
export PATH=\$PYTHON_HOME/bin:\$PATH
EOF
source /etc/profile
python3.10 --version
安装好 Python3.10.10 环境后,接着安装我们 Python 程序所需依赖。这里将会安装 virtualenv 虚拟环境,虚拟环境可以有效隔绝 Python 依赖包的冲突,同时使 Python 环境也更加干净。
# 创建Python虚拟环境
cd /opt/module/wordpress/script
# 创建一个名为venv的虚拟环境
pip3.10 install virtualenv
virtualenv venv
# 进入venv虚拟环境
source venv/bin/activate
# 在虚拟环境中安装依赖,这样依赖只会存在在该虚拟环境中
pip3.10 install oss2
# 退出虚拟环境
deactivate
Python脚本上传文件到OSS
下面将创建 Python 脚本实现上传备份文件到 OSS 存储中。
1)脚本逻辑说明
-
获取 .oss_env 中定义的变量的值。 -
创建 bucket 对象实例,压缩数据打包部分的数据并再上传到 OSS 对象存储中。
cat > /opt/module/wordpress/script/wordpress_data_oss_upload.py <<EOF
# -*- coding: utf-8 -*-
import oss2
import os
from getpass import getpass
# 通过环境变量获取配置
access_key_id = os.environ.get('OSS_ACCESS_KEY_ID')
access_key_secret = os.environ.get('OSS_ACCESS_KEY_SECRET')
endpoint = os.environ.get('OSS_ENDPOINT')
bucket_name = os.environ.get('OSS_BUCKET_NAME')
file_path = os.environ.get('OSS_LOCAL_FILE_PATH')
object_name = os.environ.get('OSS_OBJECT_NAME')
def main():
print("[DEBUG] 当前环境变量:")
print(f"ACCESS_KEY_ID: {access_key_id}")
print(f"ACCESS_KEY_SECRET: {'*' * len(access_key_secret) if access_key_secret else '未设置'}")
print(f"OSS_ENDPOINT: {endpoint}")
print(f"OSS_BUCKET_NAME: {bucket_name}")
print(f"OSS_OBJECT_NAME: {object_name}")
print(f"文件路径: {file_path}")
# 校验关键配置
if not all([access_key_id, access_key_secret]):
print("错误:缺少OSS认证信息!请设置环境变量:")
print("export OSS_ACCESS_KEY_ID='your_access_key_id'")
print("export OSS_ACCESS_KEY_SECRET='your_access_key_secret'")
return
# 创建认证对象
auth = oss2.Auth(access_key_id, access_key_secret)
bucket = oss2.Bucket(auth, f'http://{endpoint}', bucket_name)
try:
# 检查文件存在性
if not os.path.isfile(file_path):
raise FileNotFoundError(f"文件 {file_path} 不存在或不是文件")
# 执行上传
result = bucket.put_object_from_file(object_name, file_path)
if result.status == 200:
print("--------------------------------------------------")
print(f"上传成功!OSS路径:{object_name}")
print(f"ETag(完整性校验):{result.etag}")
else:
print(f"上传异常,HTTP状态码:{result.status}")
except oss2.exceptions.OssError as e:
print(f"OSS操作失败:{e.status_code} {e.code} {e.message}")
except Exception as e:
print(f"运行时错误:{str(e)}")
if __name__ == "__main__":
main()
EOF
2)定义.oss_env
用于定义我们 Python 脚本的变量值,其中OSS_LOCAL_FILE_PATH和OSS_OBJECT_NAME的值是通过引用数据打包 Shell 脚本中变量的值获取的。
PS:OSS_ENDPOINT变量值在 OSS 的概览页面下的访问端口区域获取。

cat > /opt/module/wordpress/script/.oss_env <<EOF
export OSS_ACCESS_KEY_ID="xxxx"
export OSS_ACCESS_KEY_SECRET="xxxx"
export OSS_ENDPOINT="oss-cn-xxxx.aliyuncs.com"
export OSS_BUCKET_NAME="xxxx"
export OSS_LOCAL_FILE_PATH=\${MYSQL_BACKUP_LOCAL_FILE_PATH}
export OSS_OBJECT_NAME="backup_data/wordpress_data_backup/\${MYSQL_BACKUP_FILE_NAME}"
EOF
定时任务执行脚本
1)编写定时任务执行的脚本
该脚本中会运行wordpress_db_data_backup.sh和 wordpress_data_oss_upload.py脚本。
cat > /opt/module/wordpress/script/crontab_wordpress_data_backup.sh<<EOF
unset LOCAL_PWD DB_HOST DB_USER DB_PASSWORD DB_NAME MAX_BACKUPS LOG_FILE WORDPRESS_DATA_DIR BACKUP_DIR TAR_WORDPRESS_DATA_DIR MYSQL_BACKUP_LOCAL_FILE_PATH MYSQL_BACKUP_FILE_NAME
source /opt/module/wordpress/script/wordpress_db_data_backup.sh
echo "========Python脚本上传文件到OSS========"
unset OSS_ACCESS_KEY_ID OSS_ACCESS_KEY_SECRET OSS_ENDPOINT OSS_BUCKET_NAME OSS_LOCAL_FILE_PATH OSS_OBJECT_NAME
source /opt/module/wordpress/script/venv/bin/activate
source /opt/module/wordpress/script/.oss_env && python3.10 /opt/module/wordpress/script/wordpress_data_oss_upload.py
deactivate
EOF
最终我们创建的脚本目录结构如下。

2)创建执行定时任务前,我们可以手动执行脚本看是否能成功运行。
source /opt/module/wordpress/script/crontab_wordpress_data_backup.sh

查看对象存储中的文件是否和上传的文件一致。

3)创建定时任务,每天凌晨3天执行一次备份脚本,同时将日志记录在 /var/log/wordpress_data_backup.log中。
# 编辑crontab定时任务
$ crontab -e
0 3 * * * source /opt/module/wordpress/script/crontab_wordpress_data_backup.sh >> /var/log/wordpress_data_backup.log
# 查看crontab定义的定时任务
$ crontab -l
0 3 * * * source /opt/module/wordpress/script/crontab_wordpress_data_backup.sh >> /var/log/wordpress_data_backup.log
数据恢复
在我们需要进行数据恢复时,可以进行以下操作。这里只介绍数据库的恢复,WordPress 的数据源(/opt/module/wordpress/wordpress_data)恢复可以直接将对应的备份数据全部替换掉之前的数据即可。
1)下载要恢复的数据

2)将下载的数据上传到服务器中

解压数据库文件
[root@localhost home]# tar -vzxf wordpress_data_20250513-001649.tar
./mysql-qiuyl-20250513-001649.sql.gz
./wordpress-20250513-001649.tar
[root@localhost home]# ll
total 68976
-rw-r--r-- 1 root root 240219 May 13 00:16 mysql-qiuyl-20250513-001649.sql.gz
-rw-r--r-- 1 root root 35091520 May 13 00:16 wordpress-20250513-001649.tar
-rw-r--r-- 1 root root 35292398 May 13 00:38 wordpress_data_20250513-001649.tar
[root@localhost home]# zcat mysql-qiuyl-20250513-001649.sql.gz > mysql-qiuyl-20250513-001649.sql
Tips:
# 解压文件 不保留原压缩文件
gunzip qiuyl-20250511-191450.sql.gz
# 解压文件 保留原压缩文件
zcat qiuyl-20250511-191450.sql.gz > qiuyl-20250511-191450.sql
重启服务、重新导入数据库
# 备份原有数据
cp -rf /opt/module/wordpress/mysql_data /home/mysql_data.bak
rm -rf /opt/module/wordpress/mysql_data
# 重启wordperss系统
cd /opt/module/wordpress/docker-compose
docker compose down && docker compose up -d
# 导入数据库
yum install -y mariadb
mysql -h 127.0.0.1 -u root -pmysql@qiuyl.com
MySQL [(none)]> use qiuyl
Database changed
MySQL [qiuyl]> source /home/mysql-qiuyl-20250513-001649.sql;
主机安全
这里介绍两个最基础的主机安全设置,关闭 PING 和 SSH 协议。可以隔绝我们主机 IP 暴露在外的安全风险。
1)安全组关闭 SSH 端口
注意:当我们博客系统搭建好无需其他操作之后,已经不需要频繁通过 SSH 远程连接终端操作云服务器时,可关闭 SSH 端口。当需要再次远程连接时,开启即可。
开放 22 端口前,能通。
telnet 8.152.163.1 22

关闭 22 端口后,不通。


这样我们 SSH 终端也是连接不上了。

2)禁止 ICMP 协议用于 PING 的协议
关闭 PING 协议,可以有效避免其他人进行 IP 存活扫描。
关闭 ICMP 协议前,能通。

关闭 ICMP 协议后,不通。
云服务器可以直接通过删除对应安全组关闭。


OSS安全
OSS 的安全设置,可以通过 OSS 的健康检测来判断需要设置那些安全操作,这里只介绍防盗链相关内容。
目前为止我们应该 OSS 这里创建了两个桶,一个用于图床,一个用于我们的备份存储。我们备份存储的桶,不会对外开放所以可以不用设置防盗链。但我们的图床为了不被盗刷流量,所以一定要尽快设置防盗链。具体操作直接看阿里云文档即可。
OSS 计费文档:https://help.aliyun.com/zh/oss/billing-overview?spm=a2c4g.11186623.help-menu-31815.d_2_0.79011887DNxQQU
OSS 防盗链文档:https://help.aliyun.com/zh/oss/user-guide/hotlink-protection/?spm=5176.8466032.console-base_help.dexternal.55061450sy9lzd#section-v8u-n4s-t8s

以下是我图床桶的防盗链的白名单 Referer,可参考。
*.aliyun.com
*.csdn.net
*.mdnice.com
*.nlark.com
*.qq.com
*.weixinbridge.com
*.yuque.com
https://www.qiuyl.com
https://www.qiuyl.com
总结
虽然我们已经进行了以上的安全操作,来保障我们的博客系统持续稳定的提供服务。但以上安全操作还是有限的,保守估计对于我们个人站长的安全保障应该可以避免 80-90% 的问题了。
本文中只介绍了上传文件在 OSS 存储中,为避免备份文件过多所以我们目前需要手动的去删除 OSS 中的备份文件。有的朋友会想,我们上传都可以通过程序实现,那么我们删除操作是不是同样可以呢?答案:是的。
Python 调用删除 OSS 中文件 SDK:https://help.aliyun.com/zh/oss/developer-reference/delete-objects-2?spm=a2c4g.11186623.help-menu-31815.d_5_2_2_1_5_2_6.6f231363GiUftP
删除对象存储中的操作,这里就留给大家自己去实践了。如果后续我也完善了会在该系列中添加补充内容说明。
以上就是本章的全部内容了,下一篇将是我们该系列的最后一篇内容了,将对我们该系列文进行总结。
最后。如果,你对本文有任何疑问,欢迎评论区留言、加群交流 学习、提问、分享经验。如果有帮助记得送出一个免费的
感谢!
END
非特殊说明,本博所有文章均为博主原创。
如若转载,请注明出处:https://www.qiuyl.com/video/blog/614



Abutogel: <a href=" https://abutowin.icu/# ">S...