首页
留言
导航
统计
Search
1
追番推荐!免费看动漫的网站 - 支持在线观看和磁力下载
2,510 阅读
2
推荐31个docker应用,每一个都很实用
1,311 阅读
3
PVE自动启动 虚拟机 | 容器 顺序设置及参数说明
931 阅读
4
一条命令,永久激活!Office 2024!
618 阅读
5
优选 Cloudflare 官方 / 中转 IP
490 阅读
默认分类
服务器
宝塔
VPS
Docker
OpenWRT
Nginx
群晖
前端编程
Vue
React
Angular
NodeJS
uni-app
后端编程
Java
Python
SpringBoot
SpringCloud
流程引擎
检索引擎
Linux
CentOS
Ubuntu
Debian
数据库
Redis
MySQL
Oracle
虚拟机
VMware
VirtualBox
PVE
Hyper-V
计算机
网络技术
网站源码
主题模板
登录
Search
标签搜索
Java
小程序
Redis
SpringBoot
docker
Typecho
Cloudflare
docker部署
虚拟机
WordPress
群晖
uni-app
CentOS
Vue
Java类库
Linux命令
防火墙配置
Mysql
脚本
Nginx
微醺
累计撰写
264
篇文章
累计收到
11
条评论
首页
栏目
默认分类
服务器
宝塔
VPS
Docker
OpenWRT
Nginx
群晖
前端编程
Vue
React
Angular
NodeJS
uni-app
后端编程
Java
Python
SpringBoot
SpringCloud
流程引擎
检索引擎
Linux
CentOS
Ubuntu
Debian
数据库
Redis
MySQL
Oracle
虚拟机
VMware
VirtualBox
PVE
Hyper-V
计算机
网络技术
网站源码
主题模板
页面
留言
导航
统计
搜索到
264
篇与
的结果
2026-01-22
Docker 一键部署 WireGuard VPN,支持可视化管理与监控
🌟 引言随着远程办公、跨地域访问与隐私保护需求的不断增长,VPN(虚拟专用网络) 正在成为个人与企业必备的基础设施之一。而传统的 WireGuard VPN 配置流程对于普通用户而言存在一定门槛,需要大量命令行操作与手动配置。WG-Easy 正是在这种背景下应运而生的高效解决方案,它将 WireGuard 的强大性能与可视化管理相结合,大大降低部署和维护难度。💡 项目简介WG-Easy(WireGuard Easy) 是一个将 WireGuard VPN 核心服务与 Web 可视化管理界面深度集成的开源项目。它通过直观的浏览器操作界面,让用户无需掌握复杂的命令行知识,即可快速完成 VPN 的部署、配置与监控。设计理念:📦 开箱即用:基于 Docker 容器化部署,一条命令即可启动🖱️ 可视化优先:所有操作均可在 Web 界面完成,告别配置文件🚀 性能卓越:基于 WireGuard 协议,提供媲美直连的网络速度🔒 安全可靠:采用现代密码学套件,代码简洁易审计🎯 核心特性WireGuard Easy 提供了一套完整的 VPN 管理功能,主要特性包括:🧩 一体化架构:将 WireGuard 核心 VPN 与 Web 管理界面整合在一起。🚀 快速部署:基于 Docker 容器化,一条命令即可启动完整 VPN 服务。🖥️ 可视化管理面板:客户端创建、编辑、禁用、删除全部图形化完成。📱 二维码一键接入:自动生成配置二维码,便于移动设备一键连接。🔗 一次性分享链接:生成临时配置链接,分享后自动失效,提升安全性📊 实时连接与流量监控:显示每个客户端的在线状态、上传 / 下载流量。🌗 多语言 & 深浅色模式:自动适配浏览器语言,支持暗黑模式。📈Prometheus 监控支持:原生支持 Prometheus,便于接入 Grafana 统一监控体系。🔑 双因素认证(2FA):支持 TOTP 双因素认证,提升账户安全。🔐 继承 WireGuard 的安全模型:公钥认证、现代加密算法,无密码、无证书链复杂度。ℹ️ 环境信息🔍 WireGuard 内核支持检查在部署前,请确认服务器内核已支持 WireGuard:uname -r加载 WireGuard 内核模块:modprobe wireguard验证是否成功:lsmod | grep wireguard说明:Linux Kernel ≥ 5.6 已内置 WireGuardUbuntu 20.04+ / 22.04 LTS 默认支持若加载失败,请检查内核版本或云厂商是否裁剪模块基础环境云服务器(VPS / 轻量云 / 物理机)操作系统:Ubuntu 22.04 LTS(推荐)具有域名 或 公网 IP已安装 Docker / Docker Compose网络与安全组要求UDP 51820(WireGuard 通信端口)TCP 51821(wg-easy Web 管理界面)出口网络允许访问公网(用于 VPN 转发)🔥 配置防火墙规则# Ubuntu/Debian (使用 ufw) sudo ufw allow 51820/udp comment 'WireGuard VPN' sudo ufw allow 51821/tcp comment 'WG-Easy Web UI'⚠️ 若云厂商启用防火墙 / 安全组,务必同步放行端口。📦 部署教程🚀 方式一:Docker 命令行部署(快速上手)1️⃣ 创建网络docker network create \ -d bridge --ipv6 \ --subnet 10.42.42.0/24 \ --subnet fdcc:ad94:bacf:61a3::/64 \ wg2️⃣ 启动容器docker run -d \ --net wg \ -e INSECURE=true \ --name wg-easy \ --ip6 fdcc:ad94:bacf:61a3::2a \ --ip 10.42.42.42 \ -v ~/.wg-easy:/etc/wireguard \ -v /lib/modules:/lib/modules:ro \ -p 51820:51820/udp \ -p 51821:51821/tcp \ --cap-add NET_ADMIN \ --cap-add SYS_MODULE \ --sysctl net.ipv4.ip_forward=1 \ --sysctl net.ipv4.conf.all.src_valid_mark=1 \ --sysctl net.ipv6.conf.all.disable_ipv6=0 \ --sysctl net.ipv6.conf.all.forwarding=1 \ --sysctl net.ipv6.conf.default.forwarding=1 \ --restart unless-stopped \ ghcr.io/wg-easy/wg-easy:153️⃣ 访问 Web 界面访问浏览器 http://服务器IP:51821 即可进入界面。🐳 方式二:Docker Compose 部署(推荐)1️⃣ 安装 Docker Compose# Ubuntu/Debian # sudo apt install -y docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin sudo apt install -y docker-compose-plugin2️⃣ 创建配置目录mkdir ~/wg-easy/ && mkdir ~/wg-easy/3️⃣ 下载 Docker Compose 文件sudo curl -o /etc/docker/containers/wg-easy/docker-compose.yml https://raw.githubusercontent.com/wg-easy/wg-easy/master/docker-compose.yml4️⃣ 修改配置编辑docker-compose.yml文件并取消environment注释INSECURE设置INSECURE为true允许通过非安全http连接访问 Web UI。完整 docker-compose.yml 文件如下:volumes: etc_wireguard: services: wg-easy: volumes: etc_wireguard: services: wg-easy: environment: - INSECURE=true image: ghcr.nju.edu.cn/wg-easy/wg-easy:15 container_name: wg-easy networks: wg: ipv4_address: 10.42.42.42 ipv6_address: fdcc:ad94:bacf:61a3::2a volumes: - etc_wireguard:/etc/wireguard - /lib/modules:/lib/modules:ro ports: - "51820:51820/udp" - "51821:51821/tcp" restart: unless-stopped cap_add: - NET_ADMIN - SYS_MODULE sysctls: - net.ipv4.ip_forward=1 - net.ipv4.conf.all.src_valid_mark=1 - net.ipv6.conf.all.disable_ipv6=0 - net.ipv6.conf.all.forwarding=1 - net.ipv6.conf.default.forwarding=1 networks: wg: driver: bridge enable_ipv6: true ipam: driver: default config: - subnet: 10.42.42.0/24 - subnet: fdcc:ad94:bacf:61a3::/645️⃣ 启动服务# 启动容器 docker compose up -d # 查看日志 docker compose logs -f wg-easy # 查看容器状态 docker compose ps访问浏览器 http://服务器IP:51821 即可进入界面。⚙️ 初始配置🔐 创建管理员账号📱 创建客户端配置🔀 配置路由规则(重要)修改客户端配置,添加允许的 IP ,决定哪些流量走 VPN:# 全局代理(所有流量走 VPN) 0.0.0.0/0, ::/0 # 仅访问特定网段(分流模式,推荐) 10.42.42.0/24 # WireGuard 内网 10.7.0.0/22 # 服务器内网 172.17.0.0/24 # docker 192.168.1.0/24 # 家庭网络💡 分流模式的优势:✅ 仅内网流量走 VPN,外网直连✅ 节省 VPN 服务器带宽✅ 访问国内网站速度更快保存后即可通过扫描二维码或下载配置文件连接📊 启用 Prometheus 监控1️⃣ 在 WG-Easy 中启用进入 管理面板 > 通用设置 > Prometheus,启用监控并设置密码。 2️⃣ 配置 Prometheus在 Prometheus 配置文件中添加:以下是一个示例:scrape_configs: - job_name: 'wg-easy' scrape_interval: 30s metrics_path: /metrics/prometheus static_configs: - targets: - '服务器IP:51821' authorization: type: Bearer credentials: '上一步设置的密码'导入 Grafana 仪表盘Grafana Dashboard ID:21733🖥️ 项目界面预览📊 仪表盘💻 客户端连接Windows客户端 iPhone客户端 🎯 适用场景WG-Easy 适用于多种实际应用场景,从个人隐私保护到企业级远程访问,都能提供高效的解决方案:🧑💻 远程办公 / 内网访问安全访问公司内网服务(Git、Jenkins、数据库、K8s 等)。🌍 跨地域统一出口网络多终端统一出口 IP,便于访问特定区域网络资源。🏡 家庭网络远程访问安全访问家中 NAS、路由器、智能家居设备、监控摄像头、内网服务。👥 小型团队 VPN 管理无需专业网络运维即可维护团队 VPN。🧪 测试 / 沙箱 / 运维环境快速搭建临时 VPN,随用随删,配置可追溯。🔗 相关链接📖 官方文档官方网站:https://wg-easy.github.io/wg-easy/latest/GitHub 仓库:https://github.com/wg-easy/wg-easy快速开始:https://wg-easy.github.io/wg-easy/latest/getting-started/部署示例:https://wg-easy.github.io/wg-easy/latest/examples/tutorials/basic-installation/🔧 高级配置Caddy 反向代理:https://wg-easy.github.io/wg-easy/latest/examples/tutorials/caddy/Traefik 反向代理:https://wg-easy.github.io/wg-easy/latest/examples/tutorials/traefik/可选配置项:https://wg-easy.github.io/wg-easy/latest/advanced/config/optional-config/API 接口文档:https://wg-easy.github.io/wg-easy/latest/advanced/api/📱 客户端下载平台下载地址Windowshttps://download.wireguard.com/windows-client/🍎 macOShttps://apps.apple.com/app/wireguard/id1451685025🤖 Androidhttps://play.google.com/store/apps/details?id=com.wireguard.android📱 iOShttps://apps.apple.com/app/wireguard/id1441195209🐧 Linuxsudo apt install wireguard 或各发行版包管理器💬 社区支持问题反馈:https://github.com/wg-easy/wg-easy/issues讨论区:https://github.com/wg-easy/wg-easy/discussions贡献指南:https://wg-easy.github.io/wg-easy/latest/contributing/general/WireGuard vs IPsec vs OpenVPN 核心对比选择 WireGuard,如果你需要:✅ 极致性能:低延迟、高吞吐量的网络体验✅ 移动场景:频繁切换网络(4G/5G ↔ WiFi)✅ 简单部署:快速上手,无需复杂配置✅ 物联网/嵌入式:资源受限的设备🎯 适用场景:个人 VPN、移动办公、物联网、云原生环境选择 IPsec,如果你需要:✅ 企业合规:满足 FIPS、CC 等安全认证要求✅ 站点互联:分支机构与总部的网络互联✅ 原生集成:操作系统内置支持,无需额外客户端✅ 传统设备:需要与老旧设备兼容🎯 适用场景:企业站点互联、合规要求高的场景、金融行业选择 OpenVPN,如果你需要:✅ 最大兼容性:严格的防火墙环境(可伪装 HTTPS)✅ 灵活认证:用户名密码、双因素认证等✅ 成熟生态:丰富的第三方工具和管理系统✅ 细粒度控制:复杂的访问控制和策略路由🎯 适用场景:企业远程访问、严格防火墙环境、需要灵活认证的场景🎉 总结WG-Easy 以其实用性和易用性,将传统 WireGuard VPN 的部署门槛大幅降低,使得 VPN 架构不仅对开发者友好,同时对非专业用户亦极易上手。无论是个人搭建,还是企业内网 VPN 管理,WG-Easy 都能提供简洁、高效、安全的解决方案,是值得推荐的开源 VPN 工具。
2026年01月22日
3 阅读
0 评论
0 点赞
2025-11-22
Linux环境下卸载Oracle数据库并重新安装的详细指南
引言在 Linux 环境下管理和维护 Oracle 数据库是许多系统管理员和数据库管理员的日常工作之一。无论是出于升级、迁移还是解决故障的需要,卸载和重新安装 Oracle数据库 都是一项重要的技能。本文将为您提供一份详尽的指南,帮助您在 Linux 环境下彻底卸载 Oracle数据库,并重新安装。一、准备工作在开始卸载之前,确保您已经备份了所有重要的数据文件和配置信息,以防万一。同时,确保您具有足够的权限(通常是root用户)来执行以下操作。二、停止Oracle服务停止数据库实例使用 SQL Plus 停止数据库实例sqlplus /nolog SQL> connect / as sysdba SQL> shutdown immediate SQL> exit停止Listener服务使用 lsnrctl 命令停止Listenerlsnrctl stop停止HTTP服务如果您的环境中启用了HTTP服务,停止它:service httpd stop三、卸载Oracle软件切换到root用户如果您当前不是 root 用户,请切换到 rootsu - root删除Oracle安装目录删除 Oracle 的安装目录,通常是/u01/app/oraclerm -rf /u01/app/oracle删除相关文件和目录删除与Oracle相关的文件和目录rm /usr/local/bin/dbhome rm /usr/local/bin/oraenv rm /usr/local/bin/coraenv rm /etc/oratab rm /etc/oraInst.loc删除Oracle用户和用户组删除 Oracle 用户和相关的用户组userdel -r oracle groupdel oinstall groupdel dba groupdel oper删除启动服务删除与 Oracle 相关的启动服务chkconfig --del dbora四、清理环境变量编辑 /etc/profile 或 ~/.bash_profile 文件,删除与 Oracle 相关的环境变量设置。五、重新安装Oracle数据库前置条件确保系统满足Oracle的安装要求,如磁盘空间、内存等。安装并配置好Java环境。下载Oracle数据库安装包。创建Oracle用户和用户组groupadd oinstall groupadd dba useradd -g oinstall -G dba oracle设置环境变量编辑 ~/.bash_profile 文件,添加以下内容export ORACLE_BASE=/u01/app/oracle export ORACLE_HOME=$ORACLE_BASE/product/19.0.0/dbhome_1 export ORACLE_SID=ORCL export PATH=$ORACLE_HOME/bin:$PATH安装Oracle数据库解压安装包并运行安装脚本unzip linuxx64_19c_database.zip cd database ./runInstaller按照安装向导的提示完成安装。配置数据库安装完成后,运行 root.sh 脚本/u01/app/oracle/product/19.0.0/dbhome_1/root.sh初始化数据库dbca -silent -createDatabase -templateName General_Purpose.dbc -gdbname ORCL -sid ORCL -responseFile NO_VALUE -characterSet AL32UTF8 -memoryPercentage 40 -emConfiguration LOCAL -pdbName PDBORCL -sysPassword syspassword -systemPassword systempassword六、验证安装启动数据库sqlplus /nolog SQL> connect / as sysdba SQL> startup检查数据库状态SQL> select status from v$instance;七、常见问题及解决方案libaio问题如果在启动数据库时遇到 libaio 相关的错误,安装或重新安装 libaio 库yum install libaio防火墙问题如果无法通过Navicat等工具连接数据库,检查防火墙设置或开放1521端口firewall-cmd --permanent --add-port=1521/tcp firewall-cmd --reload结语通过以上步骤,您应该能够在 Linux 环境下成功卸载并重新安装 Oracle数据库。尽管过程中可能会遇到一些问题,但只要按照指南逐步操作,大多数问题都可以得到解决;希望本文对您有所帮助,祝您工作顺利!
2025年11月22日
35 阅读
0 评论
0 点赞
2025-11-22
Oracle11.2.0.4打补丁实践
本文介绍如何给Oracle数据库打补丁,数据库版本为Oracle11.2.0.4,单实例,操作系统为CentOS7.9,Linux系统应该都可以。下载升级包因为没有MOS帐号,从网上下载了升级包p30670774_112040_Linux-x86-64.zip:数据库补丁p6880880_112000_Linux-x86-64.zip:opatch升级包百度云链接:https://pan.baidu.com/s/1ZvTQr-gI889mylgzUXkdPw提取码:plhp微云链接:https://share.weiyun.com/k8CbxL3Kopatch 是安装补丁的程序,数据库软件安装完成后,就自带了 opatch ,但是版本太旧了,所以这里下载最新的 opatch ,p6880880_112000_Linux-x86-64.zip 包就是用来升级 opatch 用的。升级opatchopatch 的升级只要将新版本的包解压,覆盖系统原始的文件即可。1.查看原始opatch信息[oracle@node1 ~]$ cd $ORACLE_HOME/OPatch [oracle@node1 OPatch]$ ./opatch version # 查看原始版本 OPatch Version: 11.2.0.3.4 OPatch succeeded.2.查看补丁情况[oracle@node1 OPatch]$ ./opatch lsinventory # 查看补丁情况 Oracle 中间补丁程序安装程序版本 11.2.0.3.4 版权所有 (c) 2012, Oracle Corporation。保留所有权利。 Oracle Home : /home/oracle/app/oracle/product/11.2.0/dbhome_1 Central Inventory : /home/oracle/app/oraInventory from : /home/oracle/app/oracle/product/11.2.0/dbhome_1/oraInst.loc OPatch version : 11.2.0.3.4 OUI version : 11.2.0.4.0 Log file location : /home/oracle/app/oracle/product/11.2.0/dbhome_1/cfgtoollogs/opatch/opatch2020-07-02_16-23-35下午_1.log Lsinventory Output file location : /home/oracle/app/oracle/product/11.2.0/dbhome_1/cfgtoollogs/opatch/lsinv/lsinventory2020-07-02_16-23-35下午.txt ---------------------------------------------------------------------------- 已安装的顶级产品 (1): Oracle Database 11g 11.2.0.4.0 此 Oracle 主目录中已安装 1 个产品。 此 Oracle 主目录中未安装任何中间补丁程序。 ---------------------------------------------------------------------------- OPatch succeeded.3.备份原opatch[oracle@node1 OPatch]$ cd $ORACLE_HOME [oracle@node1 dbhome_1]$ mv OPatch OPatch.bak4.解压新下载的opatch包将下载的 opatch 包上传到 oracle 的home目录,上传完后,解压到 $ORACLE_HOME 下[oracle@node1 dbhome_1]$ cd ~ [oracle@node1 ~]$ unzip p6880880_112000_Linux-x86-64.zip -d $ORACLE_HOME5.检查opatch是否升级成功[oracle@node1 ~]$ cd $ORACLE_HOME/OPatch [oracle@node1 OPatch]$ ./opatch version # 查看版本信息 OPatch Version: 11.2.0.3.21 OPatch succeeded.现在版本为 11.2.0.3.21,说明升级成功数据库打补丁1.关闭监听、数据库[oracle@node1 OPatch]$ lsnrctl stop # 关闭监听 [oracle@node1 ~]$ sqlplus / as sysdba SQL> shutdown immediate SQL> quit2.解压补丁包将下载的补丁包上传到 oracle home目录,并解压[oracle@node1 ~]$ cd ~ [oracle@node1 ~]$ unzip p30670774_112040_Linux-x86-64.zip3.校验冲突[oracle@node1 ~]$ cd 30670774/ [oracle@node1 30670774]$ $ORACLE_HOME/OPatch/opatch prereq CheckConflictAgainstOHWithDetail -ph ./ Oracle 临时补丁程序安装程序版本 11.2.0.3.21 版权所有 (c) 2020, Oracle Corporation。保留所有权利。 PREREQ session Oracle 主目录 :/home/oracle/app/oracle/product/11.2.0/dbhome_1 主产品清单:/home/oracle/app/oraInventory 来自 :/home/oracle/app/oracle/product/11.2.0/dbhome_1/oraInst.loc OPatch 版本 :11.2.0.3.21 OUI 版本 :11.2.0.4.0 日志文件位置:/home/oracle/app/oracle/product/11.2.0/dbhome_1/cfgtoollogs/opatch/opatch2020-07-02_16-54-06下午_1.log Invoking prereq "checkconflictagainstohwithdetail" Prereq "checkConflictAgainstOHWithDetail" passed. OPatch succeeded.由于这个测试库之前并没有打补丁,所以这里就没有补丁冲突的问题,如果这里显示有冲突,再去网MOS上查找相关解决方案。4.执行打补丁[oracle@node1 30670774]$ $ORACLE_HOME/OPatch/opatch apply这里要输入3次y和一次回车,打补丁的过程耗是比较久的,耐心等待5.检查打补丁情况[oracle@node1 30670774]$ $ORACLE_HOME/OPatch/opatch lsinventory # 检查打补丁情况这里会列出系统已打的补丁情况6.启动数据库,并运行sql文件[oracle@node1 30670774]$ cd $ORACLE_HOME/rdbms/admin [oracle@node1 30670774]$ sqlplus / as sysdba SQL> startup SQL> @catbundle.sql psu apply SQL> quit7.启动监听[oracle@node1 admin]$ lsnrctl start至此数据库打补丁已经全部完成回退数据库补丁数据库在做变更时,需要考虑回退方案,接下来介绍如何回退数据库补丁1.关闭监听、数据库[oracle@node1 ~]$ lsnrctl stop # 关闭监听 [oracle@node1 ~]$ sqlplus / as sysdba SQL> shutdown immediate SQL> quit2.回退补丁[oracle@node1 ~]$ $ORACLE_HOME/OPatch/opatch rollback -id 30670774这里要回复一次y,回退过程比较耗时,需耐心等待3.启动数据库,并运行sql文件[oracle@node1 ~]$ cd $ORACLE_HOME/rdbms/admin [oracle@node1 admin]$ sqlplus / as sysdba SQL> startup SQL> @catbundle_PSU_ORCL_ROLLBACK.sql # 这里的ORCL为实例名称 SQL> quit4.检查回退情况[oracle@node1 admin]$ $ORACLE_HOME/OPatch/opatch lsinventory # 检查打补丁情况 Oracle 临时补丁程序安装程序版本 11.2.0.3.21 版权所有 (c) 2020, Oracle Corporation。保留所有权利。 Oracle 主目录 :/home/oracle/app/oracle/product/11.2.0/dbhome_1 主产品清单:/home/oracle/app/oraInventory 来自 :/home/oracle/app/oracle/product/11.2.0/dbhome_1/oraInst.loc OPatch 版本 :11.2.0.3.21 OUI 版本 :11.2.0.4.0 日志文件位置:/home/oracle/app/oracle/product/11.2.0/dbhome_1/cfgtoollogs/opatch/opatch2020-07-02_18-24-48下午_1.log Lsinventory Output file location : /home/oracle/app/oracle/product/11.2.0/dbhome_1/cfgtoollogs/opatch/lsinv/lsinventory2020-07-02_18-24-48下午.txt -------------------------------------------------------------------------------- Local Machine Information:: Hostname: localhost ARU platform id: 226 ARU platform description:: Linux x86-64 已安装的顶级产品 (1): Oracle Database 11g 11.2.0.4.0 此 Oracle 主目录中已安装 1 个产品。 此 Oracle 主目录中未安装任何临时补丁程序。 -------------------------------------------------------------------------------- OPatch succeeded.可以看到,补丁已经被卸载了5.启动监听[oracle@node1 admin]$ lsnrctl start这样补丁回退就结束了总结本文介绍了单实例数据库打补丁的步骤,仅做参考,实际应以补丁包中的readme为准。
2025年11月22日
19 阅读
0 评论
0 点赞
2025-11-20
境外IP天天扫你网站?3步彻底封杀,还不用编译Nginx!
你的服务器是否每天被 /admin、/wp-login.php、/.env 扫描刷屏?这些攻击 90% 来自境外。如果你的业务只服务中国大陆用户,那完全没必要开放全球访问!更重要的是:你不需要编译 Nginx,不需要 MaxMind 账号,甚至不用装额外模块只需利用 亚太网络信息中心(APNIC)公开的官方 IP 数据,配合 Nginx 原生功能,3步实现精准拦截!为什么推荐 APNIC 方案?APNIC 官方方案 ✅ 完全公开免费✅ 原生支持,不需要重新编译Nginx✅ 亚太官方机构发布(数据权威性)✅ 所有 Linux + 任意 Nginx 版本实战:3 步实现“仅限中国大陆访问”📌 本方案适用于:任何 Linux 系统 + 任何来源的 Nginx(官方源、宝塔、LNMP、手动编译等)第一步:获取中国大陆 IP 段(来自 APNIC 官方)APNIC 每天更新各国 IP 分配清单,地址永久免费开放:http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest# 下载到文件 wget http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest # 直接输出到终端 curl -sSL https://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest创建自动转换脚本(保存为 /usr/local/bin/gen-cn-allow.sh):#!/bin/bash # 从 APNIC 官方数据生成 Nginx allow 规则 # 适用于任意 Linux 系统(CentOS/Ubuntu/Debian/Alma/Rocky 等) OUTPUT_DIR="/etc/nginx/conf.d" mkdir -p "$OUTPUT_DIR" echo "正在下载 APNIC 最新数据..." wget -qO- http://ftp.apnic.net/apnic/stats/apnic/delegated-apnic-latest | \ awk -F'|' ' $2 == "CN" && $3 == "ipv4" { prefix = $4; len = 32 - log($5) / log(2); print "allow " prefix "/" len ";"; } $2 == "CN" && $3 == "ipv6" { print "allow " $4 "/" $5 ";"; } ' > /tmp/cn_allow.list # 分离 IPv4 和 IPv6(避免混合导致 Nginx 报错) grep -E 'allow [0-9]+\.' /tmp/cn_allow.list > "$OUTPUT_DIR/china-ipv4.conf" grep -E 'allow [0-9a-fA-F:]+' /tmp/cn_allow.list > "$OUTPUT_DIR/china-ipv6.conf" # 添加注释头 sed -i "1i# Auto-generated from APNIC — $(date)" "$OUTPUT_DIR/china-ipv4.conf" sed -i "1i# Auto-generated from APNIC — $(date)" "$OUTPUT_DIR/china-ipv6.conf" rm -f /tmp/cn_allow.list echo "✅ 中国 IP 白名单已生成:" echo " IPv4: $OUTPUT_DIR/china-ipv4.conf" echo " IPv6: $OUTPUT_DIR/china-ipv6.conf"赋权并运行:chmod +x /usr/local/bin/gen-cn-allow.sh sudo /usr/local/bin/gen-cn-allow.sh🕒 建议每日自动更新(防止新 IP 段遗漏):echo "0 3 * * * root /usr/local/bin/gen-cn-allow.sh >/dev/null 2>&1" | sudo tee /etc/cron.d/update-cn-ip第二步:配置 Nginx 仅放行中国 IP编辑你的站点配置文件(如 /etc/nginx/conf.d/your-site.conf):server { listen 80; listen [::]:80; server_name your-domain.com; # 引入中国 IP 白名单(顺序很重要!) include /etc/nginx/conf.d/china-ipv4.conf; include /etc/nginx/conf.d/china-ipv6.conf; # 可选:放行本地回环(避免自己被拦) allow 127.0.0.1; allow ::1; # 拒绝所有未匹配的请求 deny all; location / { root /var/www/html; index index.html; # 你的其他配置... } }⚠️ 关键规则:Nginx 按顺序匹配 allow/deny,必须先写 allow,再写 deny all!第三步:重载生效 & 验证# 检查语法 nginx -t # 重载配置(平滑生效,不影响在线用户) nginx -s reload # 或 systemctl reload nginx验证方法: 国内手机 4G 访问 → 应正常打开;使用境外代理或 VPS 访问 → 应返回 403 Forbidden;查看日志:tail -f /var/log/nginx/access.log | grep '403'⚠️ 重要注意事项CDN 用户请特别注意!如果你使用了 Cloudflare、阿里云 CDN、腾讯云 CDN 等:用户真实 IP 被隐藏,Nginx 看到的是 CDN 节点 IP(多为境外);直接启用此规则会导致 所有用户被拦截!✅ 解决方案:在 CDN 后台开启 “回源携带真实IP”(如 Cloudflare 的 CF-Connecting-IP);或改用 CDN 自带的地域封禁功能(更简单可靠)。IPv6 支持按需启用若服务器未启用IPv6,可删除listen [::]:80;和china-ipv6.conf引用。性能影响极小中国大陆IP段约6000+条,Nginx 使用高效前缀匹配,实测无明显延迟。写在最后:屏蔽境外访问,不等于“技术复杂”。用官方数据 + Nginx 原生能力,就能构建一道高效、透明、低成本的“数字国境线”。你试过哪种防境外攻击的方法?有没有因为 CDN 导致误拦的经历?欢迎评论区分享!
2025年11月20日
32 阅读
0 评论
0 点赞
2025-11-15
还在手动封 IP?这 3 种 Nginx 动态封禁方案
还在靠 vim 手动加 deny 1.2.3.4 ;,然后 nginx -s reload ?不仅效率低,还容易误操作、漏封、重启抖动……别担心!本文为你带来三种真正 “动态”、无需复杂开发、生产可用的 Nginx 封 IP 方案,全部附带 完整配置 + 一行命令操作,让你的防护能力秒级生效,运维效率直接翻倍!方案一:OpenResty + Redis 毫秒级动态封禁实时生效|无需 reload|支持自动解封1. 安装 OpenResty + Redis# Ubuntu 示例 sudo apt install redis-server -y wget -O - https://openresty.org/package/pubkey.gpg | sudo gpg --dearmor -o /usr/share/keyrings/openresty-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/openresty-archive-keyring.gpg] http://openresty.org/package/debian $(lsb_release -sc) openresty" | sudo tee /etc/apt/sources.list.d/openresty.list sudo apt update && sudo apt install -y openresty2. 配置 /etc/openresty/nginx.confworker_processes auto; events { worker_connections 1024; } http { server { listen 80; location / { access_by_lua_block { local redis = require "resty.redis" local red = redis:new() red:set_timeout(1000) local ok, err = red:connect("127.0.0.1", 6379) if not ok then return end local ip = ngx.var.remote_addr if red:get("blacklist:" .. ip) ~= ngx.null then ngx.exit(403) end red:close() } proxy_pass http://127.0.0.1:8080; } } }3. 动态封/解 IP(一行命令)# 封 1 小时 redis-cli SETEX blacklist:1.2.3.4 3600 "abuse" # 解封 redis-cli DEL blacklist:1.2.3.4方案二:fail2ban + Nginx 日志 —— 自动分析恶意行为自动封|防爆破|开箱即用1. 安装 fail2bansudo apt install fail2ban -y2. 创建过滤器 /etc/fail2ban/filter.d/nginx-bad.conf[Definition] failregex = ^<HOST>.*"(GET|POST).*" (400|403|444|404) .* ignoreregex =3. 配置 jail /etc/fail2ban/jail.local[nginx-bad] enabled = true port = http,https filter = nginx-bad logpath = /var/log/nginx/access.log maxretry = 5 findtime = 600 bantime = 3600 action = iptables-multiport[name=nginx, port="80,443"]4. 启动sudo systemctl restart fail2ban注:默认用 iptables 封 IP。如坚持只用 Nginx ,请看方案三。方案三:纯 Shell + 文件驱动 —— 最简原生 Nginx 封禁零依赖|只用 Nginx|运维只需写文件核心思想: 维护一个纯文本黑名单文件:/etc/nginx/blacklist.txt(每行一个 IP)用一个 Shell 脚本自动转成 deny 配置并 reload通过 inotifywait 监听文件变化,改完即生效第一步:安装 inotify-tools(监听文件变动)sudo apt install inotify-tools -y第二步:创建黑名单目录和初始文件sudo mkdir -p /etc/nginx/dynamic echo "# 黑名单IP,每行一个,如:1.2.3.4" | sudo tee /etc/nginx/blacklist.txt sudo touch /etc/nginx/dynamic/blacklist.conf第三步:编写转换脚本 /usr/local/bin/gen_nginx_blacklist.sh#!/bin/bash INPUT="/etc/nginx/blacklist.txt" OUTPUT="/etc/nginx/dynamic/blacklist.conf" # 清空输出文件 echo "# Auto-generated from blacklist.txt. DO NOT EDIT." > "$OUTPUT" # 读取 blacklist.txt,跳过注释和空行,生成 deny 规则 while IFS= read -r line; do line=$(echo "$line" | xargs) # 去除前后空格 if [[ -n "$line" && "$line" != \#* ]]; then echo "deny $line;" >> "$OUTPUT" fi done < "$INPUT" #测试配置 & 重载 nginx -t && systemctl reload nginx赋予执行权限:sudo chmod +x /usr/local/bin/gen_nginx_blacklist.sh第四步:在 Nginx 配置中引入黑名单server { listen 80; include /etc/nginx/dynamic/blacklist.conf; # ← 关键! location / { proxy_pass http://127.0.0.1:8080; } }第五步:启动监听服务(后台运行)# 创建 systemd 服务(推荐)或直接运行: nohup inotifywait -m -e modify,move,create,delete /etc/nginx/blacklist.txt \ --format '%f' | while read file; do echo "[$(date)] blacklist.txt changed, regenerating..." /usr/local/bin/gen_nginx_blacklist.sh done &更优雅做法:写成 systemd 服务使用方式 运维只需编辑 /etc/nginx/blacklist.txt# 示例内容 1.2.3.4 5.6.7.8 192.168.100.50保存文件后,3 秒内自动封禁!无需任何命令!优点: 只需一个文本文件 + 一个 Shell 脚本完全兼容原生 Nginx三大方案怎么选?场景推荐方案高并发、API 网关、需要毫秒响应✅ 方案一(OpenResty + Redis)防暴力破解、WordPress、中小站点✅ 方案二(fail2ban)不想装新软件、只要原生 Nginx、运维习惯改文件✅✅✅ 方案三(Shell + 文件监听)写在最后:封 IP 不该是体力活!无论你是技术大牛还是初级运维,总有一款方案让你 告别手动 reload ,把时间留给更有价值的事。
2025年11月15日
12 阅读
0 评论
0 点赞
2025-11-01
从 0 搭建 Nginx 安全网关:堵住 90% 的 Web 漏洞!
你的网站是否曾被扫描出以下高危问题?🔸 Host 头注入:攻击者伪造 Host 头,窃取密码重置链接🔸 敏感文件泄露:.git、.env、backup.zip 被直接下载🔸 目录遍历:访问 /static/../../../etc/passwd🔸 Nginx 版本号暴露:让黑客精准利用已知漏洞别再依赖“防火墙万能”了!Nginx本身就是一个强大的安全网关 ,只需几行配置,就能实现企业级防护。✅ 无需额外软件✅ 零成本加固✅ 符合等保 2.0 要求今天,手把手教你从 0 搭建一个安全、干净、合规的 Nginx 网关!🛡️ 第一步:隐藏身份 —— 隐藏 Nginx 版本号攻击者第一步就是探测你的服务版本。暴露版本 = 送漏洞地图!🔧 配置方法在 nginx.conf 的 http 块中添加:server_tokens off;✅ 效果: 原响应头:Server: nginx/1.24.0 优化后:Server: nginx📌 额外建议如果使用了 error_page 自定义错误页,确保页面中也不包含版本信息!🚫 第二步:封堵入口 —— 禁止敏感文件与目录访问很多数据泄露,都是因为一个 .env 或 .git 文件被公开下载!通用防护配置(推荐放在 http 或 server 块)# 禁止访问隐藏文件(以 . 开头) location ~ /\. { deny all; return 404; } # 禁止访问特定敏感文件 location ~* \.(env|git|svn|htaccess|htpasswd|bak|log|sql|zip|tar\.gz)$ { deny all; return 403; } # 禁止访问备份文件(如 config.php.bak) location ~* \.bak$ { deny all; return 403; } # 禁止目录遍历(Nginx 默认已防,但显式加固更安全) location ~ \.\./ { deny all; return 403; }原理说明: ~ 表示正则匹配 ~* 表示不区分大小写 deny all 直接拒绝访问,不返回文件内容🌐 第三步:锁定身份 —— 防 Host 头攻击(关键!)什么是 Host 头攻击?当 Nginx 配置了宽松的 server_name(如 server_name _; 或未设置默认拒绝 server)时,攻击者可构造恶意 Host 头:GET /password-reset HTTP/1.1 Host: attacker.com如果后端代码使用 Host 头生成重置链接(如 https://attacker.com/reset?token=xxx),攻击者就能窃取用户凭证!安全配置方案1. 设置默认拒绝的 server 块在所有 server 块之前,添加一个“兜底”配置:server { listen 80 default_server; listen 443 ssl default_server; server_name _ ""; return 403; } 此配置会拒绝所有未明确匹配的域名请求。2. 明确指定合法域名在你的业务 server 块中,只允许真实域名:server { listen 80; server_name www.yourdomain.com yourdomain.com; # 你的业务配置... }3. (可选)在应用层二次校验即使 Nginx 层做了防护,后端也应校验 Host 是否在白名单内,形成纵深防御。🛠️ 第四步:添加安全响应头(提升浏览器防护)现代浏览器支持多种安全策略,通过响应头启用:add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header X-XSS-Protection "1; mode=block" always; add_header Referrer-Policy "strict-origin-when-cross-origin" always; add_header Content-Security-Policy "default-src 'self'; script-src 'self' 'unsafe-inline' https:" always;说明: X-Frame-Options: DENY:防点击劫持 X-Content-Type-Options: nosniff:防 MIME 嗅探 always:确保错误页面也携带这些头🧪 验证是否生效1. 检查版本是否隐藏curl -I http://your-domain.com→ 确保 Server 字段不含版本号。2. 测试敏感文件访问curl -I http://your-domain.com/.env→ 应返回 403 或 404,不能返回 200。3. 测试 Host 头攻击curl -H "Host: evil.com" http://your-server-ip/→ 应返回 403,而非业务页面。📋 完整安全配置模板(推荐收藏)# /etc/nginx/nginx.conf 或站点配置 # 隐藏版本 server_tokens off; # 默认拒绝 server(放在最前面!) server { listen 80 default_server; listen 443 ssl default_server; server_name _ ""; return 403; } # 业务 server server { listen 80; server_name yourdomain.com www.yourdomain.com; # 安全响应头 add_header X-Content-Type-Options "nosniff" always; add_header X-Frame-Options "DENY" always; add_header X-XSS-Protection "1; mode=block" always; # 敏感文件防护(可放 http 块全局生效) location ~ /\. { deny all; return 404; } location ~* \.(env|git|bak|log|sql|zip)$ { deny all; return 403; } # 你的业务 location... location / { proxy_pass http://backend; } }🌟 总结:安全网关 4 大核心原则原则配置要点最小暴露隐藏版本、关闭无用模块最小权限只允许合法域名、拒绝未知 Host纵深防御Nginx + 应用层双重校验主动防护添加安全头、阻断敏感路径一个配置完善的 Nginx,胜过十台 WAF!
2025年11月01日
34 阅读
0 评论
0 点赞
2025-09-28
用lucky解决飞牛、群晖等各种nas、家里云安全远程访问教程!
用 nas 一定会有远程访问的需求,这个需求有数不清的解决方法,我们今天从 “看看,摸摸,玩玩” 这三个层次来聊聊远程访问这件事,最终要为大家呈现的是用 Lucky 这个神器。很多时候,我们的在外面打开 nas 的需求就是 “看看” ,并不是针对性的要做什么, 这时候 nas 官方中继就够用;想 “摸摸” 就得用 异地组网 或者 IPv6+DDNS 这些;最终要“玩玩”时候,就得顾及安全,速度,便捷等,目前能兼顾这些需求,只能是 lucky ,别无二选。一、准备工作:1、域名:最省心的还是推荐 spaceship 去找6数字以上的xyz域名,先买1年4.77元,再续9年42.96元,总共不超过50元。为了验证,我刚才又购买了一个,确定价格没变,记住买了立马去修改DNS为Cloudflare的两条DNS记录,减少后面的等待时间。2、IPv6网络:各家情况有不同,我这是移动宽带,本来就有IPv6,我把NAS网线直接插光猫上(老光猫有路由和Wi-Fi功能)就能用IPv6网络了。很多人推荐桥接,你搞不定直接找运营商客服找人帮你弄。3、服务商:推荐使用赛博菩萨Cloudflare+国内ip优选。提前在Cloudflare添加域名,并修改域名的DNS,然后从左上角头像那里点击后进入“配置文件”,点左侧“API令牌”,以此“创建令牌”,点击第一行“编辑区域DNS”后面的使用模版,区域资源这里选择生效的域名,然后点“继续以提示摘要”,最后完成创建令牌。把这个Token复制保存,一会要用两次。二、飞牛nas安装lucky和升级飞牛nas的应用商店搜索 “lucky” 就有,直接安装即可。自己刷的armbian用casaos或者1panel应用商店也有,哪怕你装的黑群晖的机器,添加了矿神套件后,也有lucky,并且都是一键安装,这没难度。不过飞牛nas应用商店的 lucky 版本是 v2.18.2,进入应用界面并登录后会有提示Github版本是 v2.18.6,而官网官网版本是 v2.19.4。你可以按指引从官网下载文件,并上传,如果你从应用商店安装,不建议这种方式操作升级,你应用商店的lucky会变成已安装,未启用,点击会提示端口被占用,因为真正的lucky已经在正常运行,并且飞牛系统升级时候会清除这个手动升级的版本。三、Lucky的设置1、lucky安全设置进入lucky应用后,有两个安全设置,我会优先设置。第一是安全入口,原本是IP:端口的访问格式,我们自定义一个/nicai,以后访问就是IP:端口/nicai这个格式,少了安全入口只会看到“Are you ok?”的亲切问候,如果有接触过bt面板,1panel面板等网站服务器管理面板,对安全入口肯定很熟,一定程度上能提高安全性。第二个是账号和强密码,不过lucky要强密码,所有nas上你安装的第三方应用,Docker容器牵扯到访问密码的都建议强密码,能减少很多麻烦。2、lucky设置DDNS前面都是铺垫,但是对安全性很重要。这里才进入 lucky 设置的正题,按顺序进行,更容易理解它的运作机制。先到动态域名里添加 “添加任务” ,任务名称随意,托管服务商我用Cloudflare我就选它,然后在Token那里填写Cloudflare复制来的Token。再点亮IPv6这一行,其他不动,提交任务即可。多说一句, Token 的作用和你账号密码一样,你账号密码能进行所有操作,Token进去能进行特定操作,刚使用的这个Token就只是能编辑这个域名的解析记录。然后再去添加记录,就是我们指定哪些域名通过对IPv6的解析能访问到这个nas。注意,此时只是能访问nas,还没有去具体划分某个域名能访问哪个应用。这是第三步才要做的事情。现在演示,我只添加两个,我要让fn这个二级域名访问主页,想要so这个二级域名访问pansou这个Docker这个应用。如果不放心,去Cloudflare那看看,正常情况下已经自动添加的两条解析记录。3、lucky设置SSL第二步我选择先设置好SSL,因为lucky的SSL可以一键申请,自动续签,并且支持泛域名证书,所以备受推崇。在 SSL/TLS 这里点击添加证书,选择 ACME ,再选择 “Let's Encrypt” 验证方式选择 “Cloudflare” ,填写一开始我们获取的 Token (其他域名商同理)。域名列表这里填写 “*.ami.gg” 这样的格式,好处是 A.ami 和 B.ami 等所有二级域名都能用到这个证书。其他都不用填,直接提交就行。有时候2分钟就申请成功了,有时候得快10分钟,甚至有报错,那就再试一次。4、lucky设置Web规则第三步要设置的叫“反向代理”,通俗地说,“反向代理”相当于一个集团公司的总部前台。你是访客,你无法直接去拜访某一个部门负责人,你得找前台,前台内部联系这个负责人出来和你对接。“反向代理”是隐藏了真正的受访者,“正向代理”是隐藏了真正的访问者,你这会要是趴在梯子上吃外面的瓜,你用的就是“正向代理”。现在我们给这个“前台”创建规则,告诉她从这个门口(端口)进来的人,我们才接待。不是这个端口来的不归我们管。要把TLS打开,前面我们申请的SSL证书就自动起效了。都不用去操心怎么部署,这个便捷程度别家可没有。如果 so 进来了,我们把 8282 这个端口的 Docker 服务交给它,如果 fn 进来了,我们把https的 5667 入口给它。127和192的地址在这里都管用。同理,你可以为所有你的第三方应用和Docker创建这些子规则。每一个服务都能独立访问,还是自定义的地址,并且你只要把前台这个门口(端口)把好关就行。这样安全性就提高非常多了。四、测试成果访问带 8998 端口的 fn 二级域名和 so 的二级域名,可以正常访问,浏览器没有“不安全”的提示,证书信息一切正常。但是注意,我是在演示的机器,所以把端口,二级域名都展示给大家,演示完毕,这个机器就关机了所以没关系。你自己使用的nas,一定要把这个端口绝对保密,API令牌的Token绝对保密,安全入口绝对保密,二级域名保密,你也可以使用三级域名,其实用到nas的域名本身也建议你保密,不让其他人知道最好。教程到此结束,其实我们只用到 lucky 的三个主要功能,还有五六个功能我们当前不设计涉及,所以没碰它。而如果你正在用飞牛nas本身的 DDNS ,或者 DDNS-GO 这个应用,它只是实现了三个功能里的第一个动态域名的解析。最后你要是勤快点,可以凑合从飞牛nas的证书那里上传,每三个月去手动上传一次,每次上传你都得去找个地方申请,再下载,然后区分三个文件该传哪一行,这就有点劳心费神了。哪怕你用群晖,它都能让你一键搞定https访问。用lucky,就有点一劳永逸的韵味了。如果你只用DDNS,忽略SSL和端口隐患,就好似你回家推开了大门,进去歇着了,你可知道有多少人跟着你也发现了这个敞开的门,以后发生的事,就是你的故事了。
2025年09月28日
82 阅读
0 评论
0 点赞
2025-08-13
搭建私有 Linux 镜像仓库:从零到生产的完整指南(ubuntu,centos,docker)
概述为什么需要私有镜像仓库?在企业环境中,搭建私有Linux镜像仓库具有以下优势:网络优化:减少外网带宽消耗,提升下载速度安全控制:内网环境下的安全软件分发版本管理:统一管理软件包版本,确保环境一致性离线部署:支持无外网环境的软件安装成本节约:减少重复下载,节省带宽成本架构设计环境准备硬件要求组件最低配置推荐配置生产环境CPU2核4核8核+内存4GB8GB16GB+存储500GB2TB10TB+网络100Mbps1Gbps10Gbps软件环境# 操作系统:Ubuntu 22.04 LTS 或 CentOS 8 # Web服务器:Nginx # 同步工具:rsync, apt-mirror, reposync # 监控:Prometheus + Grafana目录规划# 创建目录结构 sudomkdir -p /data/mirrors/{ubuntu,centos,docker,alpine} sudomkdir -p /data/mirrors/logs sudomkdir -p /data/mirrors/scripts sudomkdir -p /etc/mirrors搭建APT私有镜像源安装apt-mirror# Ubuntu/Debian系统 sudo apt update sudo apt install -y apt-mirror nginx # 创建镜像用户 sudo useradd -r -s /bin/false -d /data/mirrors aptmirror sudochown -R aptmirror:aptmirror /data/mirrors配置apt-mirror# 编辑配置文件 sudo nano /etc/apt/mirror.list# /etc/apt/mirror.list ############# config ################## set base_path /data/mirrors/ubuntu set mirror_path $base_path/mirror set skel_path $base_path/skel set var_path $base_path/var set cleanscript $var_path/clean.sh set defaultarch amd64 set postmirror_script $var_path/postmirror.sh set run_postmirror 0 set nthreads 20 set _tilde 0 ############# end config ############## # Ubuntu 22.04 LTS (Jammy) deb http://archive.ubuntu.com/ubuntu jammy main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu jammy-updates main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu jammy-backports main restricted universe multiverse deb http://security.ubuntu.com/ubuntu jammy-security main restricted universe multiverse # Ubuntu 20.04 LTS (Focal) deb http://archive.ubuntu.com/ubuntu focal main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu focal-updates main restricted universe multiverse deb http://archive.ubuntu.com/ubuntu focal-backports main restricted universe multiverse deb http://security.ubuntu.com/ubuntu focal-security main restricted universe multiverse # 源码包(可选) # deb-src http://archive.ubuntu.com/ubuntu jammy main restricted universe multiverse # 清理脚本 clean http://archive.ubuntu.com/ubuntu clean http://security.ubuntu.com/ubuntu创建同步脚本# 创建同步脚本 sudo nano /data/mirrors/scripts/sync-ubuntu.sh#!/bin/bash # Ubuntu镜像同步脚本 set -e LOGFILE="/data/mirrors/logs/ubuntu-sync-$(date +%Y%m%d-%H%M%S).log" LOCKFILE="/var/run/ubuntu-mirror.lock" # 检查锁文件 if [ -f "$LOCKFILE" ]; then echo"同步进程已在运行,退出..." exit 1 fi # 创建锁文件 echo $$ > "$LOCKFILE" # 清理函数 cleanup() { rm -f "$LOCKFILE" } trap cleanup EXIT echo"开始Ubuntu镜像同步: $(date)" | tee -a "$LOGFILE" # 执行同步 sudo -u aptmirror apt-mirror /etc/apt/mirror.list 2>&1 | tee -a "$LOGFILE" # 更新时间戳 echo"$(date)" > /data/mirrors/ubuntu/last_update echo"Ubuntu镜像同步完成: $(date)" | tee -a "$LOGFILE" # 清理旧日志(保留30天) find /data/mirrors/logs -name "ubuntu-sync-*.log" -mtime +30 -delete # 发送通知(可选) # curl -X POST -H 'Content-type: application/json' \ # --data '{"text":"Ubuntu镜像同步完成"}' \ # YOUR_WEBHOOK_URL# 设置执行权限 sudochmod +x /data/mirrors/scripts/sync-ubuntu.sh配置Nginx# 创建Nginx配置 sudo nano /etc/nginx/sites-available/ubuntu-mirrorserver { listen80; server_name ubuntu-mirror.example.com; root /data/mirrors/ubuntu/mirror; index index.html; # 访问日志 access_log /var/log/nginx/ubuntu-mirror.access.log; error_log /var/log/nginx/ubuntu-mirror.error.log; # 基本配置 location / { autoindexon; autoindex_exact_sizeoff; autoindex_localtimeon; # 缓存配置 expires1d; add_header Cache-Control "public, immutable"; # 安全头 add_header X-Frame-Options "SAMEORIGIN"; add_header X-Content-Type-Options "nosniff"; } # 包文件缓存 location~* \.(deb|udeb|tar\.gz|tar\.xz|tar\.bz2)$ { expires7d; add_header Cache-Control "public, immutable"; } # 元数据文件 location~* (Release|Packages|Sources)$ { expires1h; add_header Cache-Control "public, must-revalidate"; } # 状态页面 location /status { alias /data/mirrors/ubuntu/; try_files /last_update =404; add_header Content-Type text/plain; } # 禁止访问隐藏文件 location~ /\. { deny all; } }# 启用站点 sudoln -s /etc/nginx/sites-available/ubuntu-mirror /etc/nginx/sites-enabled/ sudo nginx -t sudo systemctl reload nginx搭建YUM私有镜像源安装reposync# CentOS/RHEL系统 sudo yum install -y yum-utils createrepo nginx # 或者在Ubuntu上安装 sudo apt install -y yum-utils createrepo-c nginx配置YUM仓库同步# 创建CentOS 8同步脚本 sudo nano /data/mirrors/scripts/sync-centos.sh#!/bin/bash # CentOS镜像同步脚本 set -e MIRROR_BASE="/data/mirrors/centos" LOGFILE="/data/mirrors/logs/centos-sync-$(date +%Y%m%d-%H%M%S).log" LOCKFILE="/var/run/centos-mirror.lock" # 检查锁文件 if [ -f "$LOCKFILE" ]; then echo"同步进程已在运行,退出..." exit 1 fi echo $$ > "$LOCKFILE" cleanup() { rm -f "$LOCKFILE" } trap cleanup EXIT echo"开始CentOS镜像同步: $(date)" | tee -a "$LOGFILE" # 同步CentOS 8 Stream sync_centos_stream() { local version=$1 local repo_dir="$MIRROR_BASE/$version" mkdir -p "$repo_dir" # 同步各个仓库 for repo in baseos appstream extras powertools; do echo"同步 CentOS $version$repo..." | tee -a "$LOGFILE" reposync \ --download-path="$repo_dir" \ --repo="$repo" \ --arch=x86_64 \ --newest-only \ --delete \ 2>&1 | tee -a "$LOGFILE" # 创建仓库元数据 createrepo_c "$repo_dir/$repo/" 2>&1 | tee -a "$LOGFILE" done } # 同步不同版本 sync_centos_stream "8-stream" sync_centos_stream "9-stream" # 更新时间戳 echo"$(date)" > "$MIRROR_BASE/last_update" echo"CentOS镜像同步完成: $(date)" | tee -a "$LOGFILE" # 清理旧日志 find /data/mirrors/logs -name "centos-sync-*.log" -mtime +30 -delete配置YUM仓库文件# 创建仓库配置模板 sudo nano /data/mirrors/centos/centos8-stream.repo[baseos] name=CentOS Stream $releasever - BaseOS baseurl=http://your-mirror.example.com/centos/8-stream/baseos/ gpgcheck=1 enabled=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial [appstream] name=CentOS Stream $releasever - AppStream baseurl=http://your-mirror.example.com/centos/8-stream/appstream/ gpgcheck=1 enabled=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial [extras] name=CentOS Stream $releasever - Extras baseurl=http://your-mirror.example.com/centos/8-stream/extras/ gpgcheck=1 enabled=1 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficial [powertools] name=CentOS Stream $releasever - PowerTools baseurl=http://your-mirror.example.com/centos/8-stream/powertools/ gpgcheck=1 enabled=0 gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-centosofficialNginx配置(CentOS)server { listen80; server_name centos-mirror.example.com; root /data/mirrors/centos; index index.html; access_log /var/log/nginx/centos-mirror.access.log; error_log /var/log/nginx/centos-mirror.error.log; location / { autoindexon; autoindex_exact_sizeoff; autoindex_localtimeon; expires1d; add_header Cache-Control "public, immutable"; } # RPM包缓存 location~* \.rpm$ { expires7d; add_header Cache-Control "public, immutable"; } # 元数据缓存 location~* (repomd\.xml|primary\.xml|filelists\.xml|other\.xml)$ { expires1h; add_header Cache-Control "public, must-revalidate"; } # 仓库配置文件下载 location /repo-files/ { alias /data/mirrors/centos/; try_files$uri$uri.repo =404; add_header Content-Type text/plain; } }搭建Docker私有镜像仓库安装Docker Registry# 安装Docker curl -fsSL https://get.docker.com | sh sudo usermod -aG docker $USER # 创建Registry目录 sudomkdir -p /data/mirrors/docker/{registry,auth,certs}配置Registry# 创建Registry配置文件 sudo nano /data/mirrors/docker/config.ymlversion:0.1 log: accesslog: disabled:false level:info formatter:text fields: service:registry storage: cache: blobdescriptor:inmemory filesystem: rootdirectory:/var/lib/registry delete: enabled:true http: addr::5000 headers: X-Content-Type-Options: [nosniff] Access-Control-Allow-Origin: ['*'] Access-Control-Allow-Methods: ['HEAD', 'GET', 'OPTIONS', 'DELETE'] Access-Control-Allow-Headers: ['Authorization', 'Accept', 'Cache-Control'] health: storagedriver: enabled:true interval:10s threshold:3 proxy: remoteurl:https://registry-1.docker.io username:your-dockerhub-username password:your-dockerhub-password启动Registry服务# 创建docker-compose文件 sudo nano /data/mirrors/docker/docker-compose.ymlversion:'3.8' services: registry: image:registry:2.8 container_name:docker-registry restart:unless-stopped ports: -"5000:5000" environment: REGISTRY_CONFIG_PATH:/etc/docker/registry/config.yml REGISTRY_STORAGE_FILESYSTEM_ROOTDIRECTORY:/var/lib/registry volumes: -/data/mirrors/docker/registry:/var/lib/registry -/data/mirrors/docker/config.yml:/etc/docker/registry/config.yml:ro networks: -registry-net registry-ui: image:joxit/docker-registry-ui:latest container_name:registry-ui restart:unless-stopped ports: -"8080:80" environment: REGISTRY_TITLE:"Private Docker Registry" REGISTRY_URL:http://registry:5000 DELETE_IMAGES:"true" SHOW_CONTENT_DIGEST:"true" depends_on: -registry networks: -registry-net networks: registry-net: driver:bridge# 启动服务 cd /data/mirrors/docker sudo docker-compose up -d配置Registry代理# Docker Registry Nginx配置 server { listen80; server_name docker-registry.example.com; client_max_body_size0; chunked_transfer_encodingon; location /v2/ { proxy_pass http://localhost:5000; proxy_set_header Host $http_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; proxy_read_timeout900; } location / { proxy_pass http://localhost:8080; proxy_set_header Host $http_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; } }自动化同步与更新创建统一同步脚本# 创建主同步脚本 sudo nano /data/mirrors/scripts/sync-all.sh#!/bin/bash # 统一镜像同步脚本 set -e SCRIPT_DIR="/data/mirrors/scripts" LOG_DIR="/data/mirrors/logs" NOTIFICATION_URL="${WEBHOOK_URL:-}" # 日志函数 log() { echo"[$(date '+%Y-%m-%d %H:%M:%S')] $1" | tee -a "$LOG_DIR/sync-all.log" } # 通知函数 notify() { local message="$1" local status="$2" log"$message" if [ -n "$NOTIFICATION_URL" ]; then curl -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"$message\", \"status\":\"$status\"}" \ "$NOTIFICATION_URL" || true fi } # 执行同步任务 run_sync() { local script="$1" local name="$2" if [ -f "$script" ]; then log"开始同步 $name" if"$script"; then notify "$name 同步成功""success" else notify "$name 同步失败""error" return 1 fi else log"同步脚本不存在: $script" return 1 fi } # 主执行流程 main() { log"开始镜像同步任务" local failed=0 # 同步Ubuntu run_sync "$SCRIPT_DIR/sync-ubuntu.sh""Ubuntu" || ((failed++)) # 同步CentOS run_sync "$SCRIPT_DIR/sync-centos.sh""CentOS" || ((failed++)) # 清理旧日志 find "$LOG_DIR" -name "*.log" -mtime +30 -delete if [ $failed -eq 0 ]; then notify "所有镜像同步完成""success" else notify "有 $failed 个镜像同步失败""warning" fi log"镜像同步任务结束" } main "$@"配置定时任务# 编辑crontab sudo crontab -e # 添加定时任务 # 每天凌晨2点同步 0 2 * * * /data/mirrors/scripts/sync-all.sh # 每周日凌晨1点清理Docker Registry 0 1 * * 0 /data/mirrors/scripts/cleanup-docker.sh # 每小时检查服务状态 0 * * * * /data/mirrors/scripts/health-check.sh健康检查脚本# 创建健康检查脚本 sudo nano /data/mirrors/scripts/health-check.sh#!/bin/bash # 服务健康检查脚本 SERVICES=("nginx""docker") LOG_FILE="/data/mirrors/logs/health-check.log" log() { echo"[$(date '+%Y-%m-%d %H:%M:%S')] $1" >> "$LOG_FILE" } check_service() { local service="$1" if systemctl is-active --quiet "$service"; then log"$service 服务正常运行" return 0 else log"$service 服务异常,尝试重启" systemctl restart "$service" sleep 5 if systemctl is-active --quiet "$service"; then log"$service 服务重启成功" return 0 else log"$service 服务重启失败" return 1 fi fi } check_disk_space() { local usage=$(df /data/mirrors | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$usage" -gt 85 ]; then log"磁盘空间不足: ${usage}%" # 发送告警 return 1 else log"磁盘空间正常: ${usage}%" return 0 fi } # 主检查流程 main() { local failed=0 # 检查服务状态 for service in"${SERVICES[@]}"; do check_service "$service" || ((failed++)) done # 检查磁盘空间 check_disk_space || ((failed++)) # 检查网络连通性 if ! curl -s --max-time 10 http://localhost/status > /dev/null; then log"Web服务访问异常" ((failed++)) fi if [ $failed -eq 0 ]; then log"所有检查项正常" else log"发现 $failed 个异常项" fi } main "$@"高可用与负载均衡配置HAProxy负载均衡# 安装HAProxy sudo apt install -y haproxy # 配置HAProxy sudo nano /etc/haproxy/haproxy.cfgglobal daemon chroot /var/lib/haproxy stats socket /run/haproxy/admin.sock mode 660 level admin stats timeout 30s user haproxy group haproxy defaults mode http timeout connect 5000ms timeout client 50000ms timeout server 50000ms option httplog option dontlognull errorfile 400 /etc/haproxy/errors/400.http errorfile 403 /etc/haproxy/errors/403.http errorfile 408 /etc/haproxy/errors/408.http errorfile 500 /etc/haproxy/errors/500.http errorfile 502 /etc/haproxy/errors/502.http errorfile 503 /etc/haproxy/errors/503.http errorfile 504 /etc/haproxy/errors/504.http frontend mirror_frontend bind *:80 bind *:443 ssl crt /etc/ssl/certs/mirror.pem redirect scheme https if !{ ssl_fc } # 根据域名分发 acl is_ubuntu hdr(host) -i ubuntu-mirror.example.com acl is_centos hdr(host) -i centos-mirror.example.com acl is_docker hdr(host) -i docker-registry.example.com use_backend ubuntu_backend if is_ubuntu use_backend centos_backend if is_centos use_backend docker_backend if is_docker default_backend ubuntu_backend backend ubuntu_backend balance roundrobin option httpchk GET /status server ubuntu1 192.168.1.10:80 check server ubuntu2 192.168.1.11:80 check backup backend centos_backend balance roundrobin option httpchk GET /status server centos1 192.168.1.10:80 check server centos2 192.168.1.11:80 check backup backend docker_backend balance roundrobin option httpchk GET /v2/ server docker1 192.168.1.10:5000 check server docker2 192.168.1.11:5000 check backup listen stats bind *:8404 stats enable stats uri /stats stats refresh 30s stats admin if TRUE配置Keepalived高可用# 安装Keepalived sudo apt install -y keepalived # 主节点配置 sudo nano /etc/keepalived/keepalived.conf# 主节点配置 vrrp_script chk_haproxy { script "/bin/kill -0 `cat /var/run/haproxy.pid`" interval 2 weight 2 fall 3 rise 2 } vrrp_instance VI_1 { state MASTER interface eth0 virtual_router_id 51 priority 101 advert_int 1 authentication { auth_type PASS auth_pass 1111 } virtual_ipaddress { 192.168.1.100 } track_script { chk_haproxy } }监控与维护配置Prometheus监控# 创建Prometheus配置 sudo nano /etc/prometheus/prometheus.ymlglobal: scrape_interval:15s evaluation_interval:15s rule_files: -"mirror_rules.yml" scrape_configs: -job_name:'prometheus' static_configs: -targets: ['localhost:9090'] -job_name:'node-exporter' static_configs: -targets: ['localhost:9100'] -job_name:'nginx' static_configs: -targets: ['localhost:9113'] -job_name:'haproxy' static_configs: -targets: ['localhost:8404'] alerting: alertmanagers: -static_configs: -targets: -alertmanager:9093创建告警规则# 创建告警规则 sudo nano /etc/prometheus/mirror_rules.ymlgroups: -name:mirror_alerts rules: -alert:HighDiskUsage expr:(node_filesystem_size_bytes{mountpoint="/data"}-node_filesystem_free_bytes{mountpoint="/data"})/node_filesystem_size_bytes{mountpoint="/data"}*100>85 for:5m labels: severity:warning annotations: summary:"磁盘使用率过高" description:"镜像存储磁盘使用率超过85%" -alert:ServiceDown expr:up==0 for:2m labels: severity:critical annotations: summary:"服务不可用" description:"{{ $labels.instance }} 服务已停止" -alert:HighMemoryUsage expr:(1-(node_memory_MemAvailable_bytes/node_memory_MemTotal_bytes))*100>90 for:5m labels: severity:warning annotations: summary:"内存使用率过高" description:"内存使用率超过90%" -alert:SyncJobFailed expr:increase(sync_job_failures_total[1h])>0 for:0m labels: severity:critical annotations: summary:"镜像同步失败" description:"镜像同步任务执行失败"Grafana仪表板{ "dashboard":{ "id":null, "title":"Linux Mirror Repository Dashboard", "tags":["mirror","linux"], "timezone":"browser", "panels":[ { "title":"磁盘使用率", "type":"stat", "targets":[ { "expr":"(node_filesystem_size_bytes{mountpoint=\"/data\"} - node_filesystem_free_bytes{mountpoint=\"/data\"}) / node_filesystem_size_bytes{mountpoint=\"/data\"} * 100", "legendFormat":"磁盘使用率" } ], "fieldConfig":{ "defaults":{ "unit":"percent", "thresholds":{ "steps":[ {"color":"green","value":null}, {"color":"yellow","value":70}, {"color":"red","value":85} ] } } } }, { "title":"网络流量", "type":"graph", "targets":[ { "expr":"rate(node_network_receive_bytes_total{device=\"eth0\"}[5m])", "legendFormat":"接收" }, { "expr":"rate(node_network_transmit_bytes_total{device=\"eth0\"}[5m])", "legendFormat":"发送" } ] }, { "title":"同步状态", "type":"table", "targets":[ { "expr":"sync_last_success_timestamp_seconds", "legendFormat":"最后同步时间" } ] } ], "time":{ "from":"now-1h", "to":"now" }, "refresh":"30s" } }安全配置SSL/TLS配置# 生成SSL证书 sudo openssl req -x509 -nodes -days 365 -newkey rsa:2048 \ -keyout /etc/ssl/private/mirror.key \ -out /etc/ssl/certs/mirror.crt \ -subj "/C=CN/ST=Beijing/L=Beijing/O=Company/CN=mirror.example.com" # 合并证书文件(HAProxy使用) sudocat /etc/ssl/certs/mirror.crt /etc/ssl/private/mirror.key > /etc/ssl/certs/mirror.pem访问控制# IP白名单配置 geo$allowed_ip { default0; 192.168.0.0/16 1; 10.0.0.0/8 1; 172.16.0.0/12 1; } server { listen80; server_name mirror.example.com; # IP访问控制 if ($allowed_ip = 0) { return403; } # 限制连接数 limit_conn_zone$binary_remote_addr zone=conn_limit_per_ip:10m; limit_conn conn_limit_per_ip 10; # 限制请求频率 limit_req_zone$binary_remote_addr zone=req_limit_per_ip:10m rate=10r/s; limit_req zone=req_limit_per_ip burst=20 nodelay; location / { # 基本认证(可选) auth_basic"Private Mirror"; auth_basic_user_file /etc/nginx/.htpasswd; # 其他配置... } }防火墙配置# UFW防火墙配置 sudo ufw default deny incoming sudo ufw default allow outgoing # 允许SSH sudo ufw allow ssh # 允许HTTP/HTTPS sudo ufw allow 80/tcp sudo ufw allow 443/tcp # 允许内网访问 sudo ufw allow from 192.168.0.0/16 to any port 80 sudo ufw allow from 10.0.0.0/8 to any port 80 # 启用防火墙 sudo ufw enable故障排除常见问题诊断1. 同步失败问题# 检查网络连通性 curl -I http://archive.ubuntu.com/ubuntu/ # 检查磁盘空间 df -h /data/mirrors # 检查权限 ls -la /data/mirrors/ # 查看同步日志 tail -f /data/mirrors/logs/ubuntu-sync-*.log2. 服务访问问题# 检查Nginx状态 sudo systemctl status nginx sudo nginx -t # 检查端口监听 sudo netstat -tlnp | grep :80 # 检查防火墙 sudo ufw status # 测试本地访问 curl -I http://localhost/3. 性能问题# 检查系统负载 top htop iotop # 检查网络流量 iftop nethogs # 检查磁盘IO iostat -x 1故障恢复脚本# 创建故障恢复脚本 sudo nano /data/mirrors/scripts/recovery.sh#!/bin/bash # 故障恢复脚本 SERVICES=("nginx""docker""haproxy") BACKUP_DIR="/data/backup" # 服务恢复 recover_services() { for service in"${SERVICES[@]}"; do if ! systemctl is-active --quiet "$service"; then echo"恢复服务: $service" systemctl restart "$service" sleep 5 if systemctl is-active --quiet "$service"; then echo"$service 恢复成功" else echo"$service 恢复失败" fi fi done } # 配置文件恢复 recover_configs() { if [ -d "$BACKUP_DIR" ]; then echo"恢复配置文件..." # 恢复Nginx配置 if [ -f "$BACKUP_DIR/nginx.conf" ]; then cp"$BACKUP_DIR/nginx.conf" /etc/nginx/nginx.conf nginx -t && systemctl reload nginx fi # 恢复HAProxy配置 if [ -f "$BACKUP_DIR/haproxy.cfg" ]; then cp"$BACKUP_DIR/haproxy.cfg" /etc/haproxy/haproxy.cfg systemctl reload haproxy fi fi } # 数据完整性检查 check_data_integrity() { echo"检查数据完整性..." # 检查Ubuntu镜像 if [ -f "/data/mirrors/ubuntu/mirror/dists/jammy/Release" ]; then echo"Ubuntu镜像完整" else echo"Ubuntu镜像损坏,需要重新同步" /data/mirrors/scripts/sync-ubuntu.sh fi # 检查CentOS镜像 if [ -f "/data/mirrors/centos/8-stream/baseos/repodata/repomd.xml" ]; then echo"CentOS镜像完整" else echo"CentOS镜像损坏,需要重新同步" /data/mirrors/scripts/sync-centos.sh fi } # 主恢复流程 main() { echo"开始故障恢复..." recover_services recover_configs check_data_integrity echo"故障恢复完成" } main "$@"监控脚本# 创建监控脚本 sudo nano /data/mirrors/scripts/monitor.sh#!/bin/bash # 实时监控脚本 ALERT_EMAIL="admin@example.com" WEBHOOK_URL="https://hooks.slack.com/services/YOUR/WEBHOOK/URL" send_alert() { local message="$1" local severity="$2" echo"[$(date)] ALERT [$severity]: $message" # 发送邮件告警 echo"$message" | mail -s "Mirror Alert [$severity]""$ALERT_EMAIL" # 发送Webhook通知 curl -X POST -H 'Content-type: application/json' \ --data "{\"text\":\"$message\", \"severity\":\"$severity\"}" \ "$WEBHOOK_URL" } # 检查磁盘空间 check_disk() { local usage=$(df /data/mirrors | awk 'NR==2 {print $5}' | sed 's/%//') if [ "$usage" -gt 90 ]; then send_alert "磁盘空间严重不足: ${usage}%""CRITICAL" elif [ "$usage" -gt 80 ]; then send_alert "磁盘空间不足: ${usage}%""WARNING" fi } # 检查同步状态 check_sync() { local last_sync=$(stat -c %Y /data/mirrors/ubuntu/last_update 2>/dev/null || echo 0) local current_time=$(date +%s) local diff=$((current_time - last_sync)) # 如果超过24小时未同步 if [ $diff -gt 86400 ]; then send_alert "Ubuntu镜像同步超时: $((diff/3600))小时""WARNING" fi } # 检查服务状态 check_services() { local services=("nginx""docker") for service in"${services[@]}"; do if ! systemctl is-active --quiet "$service"; then send_alert "$service 服务异常""CRITICAL" fi done } # 主监控循环 main() { whiletrue; do check_disk check_sync check_services sleep 300 # 5分钟检查一次 done } main "$@"总结通过本文的详细指南,我们成功搭建了一个完整的私有 Linux 镜像仓库系统,包括:核心功能• 多发行版支持:Ubuntu、CentOS、Docker镜像• 自动化同步:定时同步上游镜像源• 负载均衡:HAProxy + Keepalived高可用方案• 监控告警:Prometheus + Grafana监控体系运维特性• 安全加固:SSL/TLS、访问控制、防火墙配置• 故障恢复:自动化故障检测和恢复机制• 性能优化:缓存策略、并发控制• 日志管理:完整的日志记录和轮转最佳实践定期备份:配置文件和关键数据的定期备份容量规划:根据使用情况合理规划存储容量网络优化:配置适当的缓存和CDN策略安全更新:及时更新系统和软件包这套方案可以满足企业级的私有镜像仓库需求,提供稳定、高效、安全的软件包分发服务。
2025年08月13日
29 阅读
0 评论
1 点赞
2025-07-21
xiaomi 小米手机免授权免登陆刷机工具 MiFlash Prime Edition
刷机有风险,能自己承担后果再尝试,出问题概不负责!小米刷机工具 MiFlash Prime Edition 2024.08.01 (修改版) ,9008免授权免登陆刷机。小米 Mi Flash Tool 2023.4.14.0 的特点免授权刷机 (9008 EDL 模式)无需登陆账号刷机文件名称:MiFlash Prime Edition 2024.08.01.0.zip发布时间:2024.08.01文件大小:95.5M链接: https://pan.baidu.com/s/1miwwzriTpijaJ6BVhiu3jA?pwd=8888提取码: 8888步骤 1 安装驱动下载并解压刷机工具,双击“XiaoMiFlash.exe”运行,点击【Driver】弹出窗口后点击【安装】已经安装过的可以略过此步步骤 2 手机进入Fastboot模式在手机上操作 关机状态下,同时按住 音量下 + 电源键,进入 Fastboot 模式,将手机USB连接电脑。步骤 3 解压固件线刷包下载完成后解压,打开线刷包文件夹,复制地址栏地址如下图。步骤 4 准备刷机将刚才复制的路径内容粘贴到蓝色区域位置。点击黄色圈选部分加载设备,刷机程序会自动识别手机。点击红色圈选部分刷机开始刷机。有BL锁机型默认会选择“全部删除并LOCK”,没有BL锁机型需要手动选择“全部删除”(如图绿框显示)。步骤 5 刷机成功然后等待,如图表示已经刷机成功,手机会自动开机。结尾刷机有风险,能自己承担后果再尝试,出问题概不负责!
2025年07月21日
161 阅读
0 评论
0 点赞
2025-07-10
无感刷新Token:如何做到让用户“永不掉线”
没有什么比在用户操作得正嗨时,突然提示 “登录已过期,请重新登录” 的提示更让人沮丧的了。这种突兀的中断不仅破坏了用户体验,甚至可能导致未保存的数据丢失。然而,我们都知道,出于安全考虑,用于身份验证的 Token(通常是 Access Token) 必须有较短的有效期。那么,我们如何在保证安全的前提下,创造一种 “永不掉线” 的丝滑体验呢?问题的根源:Access Token 的“天生矛盾”首先,我们要理解为什么需要刷新 Token 。我们通常使用 Access Token 来验证用户的每一次 API 请求。为了安全,Access Token 的生命周期被设计得很短(例如 30 分钟或 1 小时)。如果有效期太长,一旦泄露,攻击者就能在很长一段时间内冒充用户进行操作,风险极高。这就产生了一个矛盾:安全性要求:Access Token 有效期要短。用户体验要求:用户不想频繁地被强制重新登录。为了解决这个矛盾,Refresh Token 应运而生。核心理念:双 Token 认证系统无感刷新机制的核心在于引入了两种类型的 Token:Access Token(访问令牌)用途:用于访问受保护的 API 资源,附加在每个请求的 Header 中。特点:生命周期短(如 1 小时),无状态,服务器无需存储。存储:通常存储在客户端内存中(如 Vuex/Redux),因为需要频繁读取。Refresh Token(刷新令牌)用途:当 Access Token 过期时,专门用于获取一个新的 Access Token。特点:生命周期长(如 7 天或 30 天),与特定用户绑定,服务器需要安全存储其有效性记录。存储:必须安全存储。最佳实践是存储在 HttpOnly Cookie 中,这样可以防止客户端 JavaScript 脚本(如 XSS 攻击)读取它。既然如此,为何不直接使用 Refresh Token 呢?Access Token 通常是无状态的,服务器无需记录它,也导致 JWT 无法主动吊销,而 Refresh Token 是有状态的,服务器需要一个列表(数据库中的“白名单”或“吊销列表”)来记录哪些 Refresh Token 是有效的,当用户更改密码、或从某个设备上“主动登出”时,服务器端可以主动将对应的 Refresh Token 设为无效。无感刷新的详细工作流下面是这个“魔法”发生的具体步骤:首次登录:用户使用用户名和密码登录。服务器验证成功后,返回一个 Access Token 和一个 Refresh Token。正常请求:客户端将 Access Token 存储起来,并在后续的每次 API 请求中,通过 Authorization 请求头将其发送给服务器。Token过期:当 Access Token 过期后,客户端再次用它请求 API。服务器会拒绝该请求,并返回一个特定的状态码,通常是 401 Unauthorized。拦截401错误:客户端的请求层(如 Axios 拦截器)会捕获这个 401 错误。此时,它不会立即通知用户“你已掉线”,而是暂停这个失败的请求。发起刷新请求:拦截器使用 Refresh Token 去调用一个专门的刷新接口(例如 /api/auth/refresh)。处理刷新结果:刷新成功:服务器验证 Refresh Token 有效,生成一个新的 Access Token(有时也会返回一个新的 Refresh Token,这被称为“刷新令牌旋转”策略,可以提高安全性),并将其返回给客户端。刷新失败:如果 Refresh Token 也过期了或无效,服务器会返回错误(如 403 Forbidden)。这意味着用户的登录会话彻底结束。重试与终结:若刷新成功:客户端用新的 Access Token 自动重发刚才失败的那个 API 请求。用户完全感觉不到任何中断,数据操作无缝衔接。若刷新失败:客户端清除所有认证信息,强制用户登出,并重定向到登录页面。实战演练:使用 Axios 拦截器实现无感刷新Axios 的拦截器是实现这一流程的完美工具。下面是一个完整且考虑了并发问题的实现方案。1. 创建 Axios 实例首先,我们创建一个单独的 Axios 实例,方便统一管理。// api/request.js import axios from 'axios'; const service = axios.create({ baseURL: '/api', timeout: 10000, }); // 请求拦截器 service.interceptors.request.use( config => { // 在发送请求之前,从 state management (e.g., Vuex/Pinia/Redux) 获取 token const accessToken = getAccessTokenFromStore(); if (accessToken) { config.headers['Authorization'] = `Bearer ${accessToken}`; } return config; }, error => { return Promise.reject(error); } );2. 核心:响应拦截器这是实现无感刷新的关键。// api/request.js (续) // 用于刷新 token 的 API import { refreshTokenApi } from './auth'; let isRefreshing = false; // 控制刷新状态的标志 let requests = []; // 存储因 token 过期而挂起的请求 service.interceptors.response.use( response => response, // 对成功响应直接返回 async error => { const { config, response: { status } } = error; // 1. 如果不是 401 错误,直接返回错误 if (status !== 401) { return Promise.reject(error); } // 2. 避免重复刷新:如果正在刷新 token,将后续请求暂存 if (isRefreshing) { return new Promise(resolve => { requests.push(() => resolve(service(config))); }); } isRefreshing = true; try { // 3. 调用刷新 token 的 API const { newAccessToken } = await refreshTokenApi(); // 假设 refresh token 通过 HttpOnly cookie 自动发送 // 4. 更新本地存储的 access token setAccessTokenInStore(newAccessToken); // 5. 重试刚才失败的请求 config.headers['Authorization'] = `Bearer ${newAccessToken}`; // 6. 重新执行所有被挂起的请求 requests.forEach(cb => cb()); requests = []; // 清空队列 return service(config); // 返回重试请求的结果 } catch (refreshError) { // 7. 如果刷新 token 也失败了,则执行登出操作 console.error('Unable to refresh token.', refreshError); logoutUser(); // 清除 token,重定向到登录页 return Promise.reject(refreshError); } finally { isRefreshing = false; } } ); export default service;代码解析:并发处理:isRefreshing 标志和 requests 数组是关键。当第一个 401 错误触发刷新时,isRefreshing 变为 true。后续在刷新完成前到达的 401 请求,都会被推进 requests 队列中挂起,而不是重复发起刷新请求。当刷新成功后,再遍历队列,依次执行这些被挂起的请求。原子操作:通过这种“加锁”机制,确保了刷新 Token 的操作是原子的,避免了资源浪费和潜在的竞态条件。优雅降级:当 Refresh Token 也失效时,系统会执行 logoutUser(),进行清理工作并引导用户重新登录,这是一个优雅的失败处理方案。无感刷新 Token 机制是现代 Web 应用提升用户体验的“标配”。它将身份验证的复杂性隐藏在后台,为用户提供了一个流畅、不间断的操作环境。实现这一机制,不仅仅是写几行代码,更是对认证流程、安全性和用户体验三者之间平衡的深刻理解。
2025年07月10日
35 阅读
0 评论
0 点赞
1
2
...
27