本分类专注于记录学习Linux系统的点滴。涵盖了Linux基础操作、命令行使用技巧、系统管理与优化、服务器部署等内容。无论是初学者还是有经验的用户，都可以在这里找到实用的经验分享和问题解决方案，帮助更高效地掌握Linux系统。
【全网首发】极限低成本吃满阿里云 CDT 200G 高速流量：Alpine 作为救援系统，一键重装 Debian（修复 GRUB / 清理 isohybrid 残留全流程）
更新（2026.01.10）： 重要提示：从自制镜像中读取到的 alpine virt iso 救援系统，在 VNC 执行 setup-alpine，将正式系统写入到硬盘后，该临时系统还运行在内存中，必须要重启！必须要重启！必须要重启！重启后进入到的 alpine 系统，才是从系统硬盘中读取的正式系统，才可以进行设置 DNS、配置源、清除硬盘标签、执行脚本重装等后续工作。 更新（2026.01.06）： 援引源网站证书于 2026 年 1 月 4 日失效，且网站开启了 HSTS，无法为此网站添加例外以访问，web archive 里也没有存档，我保存了一份在本地，看来得补档了。 已补档至本站。 援引 & 致谢： 使用阿里云CDT 享受每月200G/4元高速流量 如果以上链接无法打开，请访问本站补档： 【补档】使用阿里云CDT 享受每月200G/4元高速流量 补正：援引文章“五. 安装系统” → 过程 → 一：安装”中的“这样配置好用户名和密码及时区，代理跳过”文字下方的流程演示有一个坑，需要我们手动回避，在选择 APK Mirror 的时候，一定要摁“(s) Show mirror list”，然后按空格翻页，找到阿里云（aliyun）镜像源所属的序号，再做选择，如果只按原文图示直接按“49”，有可能会连接到一个速度极慢的源，因为这个镜像列表是实时更新的，截止我做测试时，阿里云的镜像源序号是“44”，这个序号未来还会根据该列表的更新而随时变化，切勿刻舟求剑。本篇教程的目的，是我们用自制镜像，启动阿里云极低配置的抢占式实例后，需要在新安装的系统内，清除掉手动安装 Alpine Linux virt 版后，其为了兼容性而在硬盘上，打了 gpt 分区、iso 镜像的标签，进而导致我们手动修复 grub 受阻，使重装系统脚本失效，为什么不用阿里云自带的重装功能，非要自己挂载镜像安装？ 援引文章里说了，官方镜像的使用条件，最低要求 20GB 硬盘才能灌入系统，即使是社区镜像，最低也要 16 GB 硬盘，硬盘容量越低，使用费用越低，16 GB 还是太大，缩减到 10 GB，甚至是 5 GB，并且能用脚本自由重装系统，才是我们的目标。教程成果 check list： wipefs -n /dev/vda 仅剩 dos 执行 grub-install /dev/vda 无报错 存在 /boot/grub/grub.cfg 重启出现 grub 菜单，并能被引导进入系统 声明：本教程案例系统盘为“vda”及“/dev/vda”，强烈建议先确认系统盘设备名。lsblk -o NAME,SIZE,TYPE,MOUNTPOINT,FSTYPE 若系统盘不是 /dev/vda（如 /dev/sda 或 /dev/nvme0n1），则以下所有命令中的 vda 需替换，后续 dd 命令执行的是破坏性写入操作，操作前请务必确认好扇区起始位置、目标硬盘、扇区计数等参数，由于个人失误造成的操作系统无法重启、数据损坏等后果自负，切勿盲目照抄。由于修改的主要是磁盘头部扇区数据，所以理论上低于 10 GB 以下的硬盘也可以按本 SOP 指示完成操作。安装好 alpine 并重启后的操作： 更新源 apk update 安装编辑器 apk add vim 启用更多源 开启社区源。vim /etc/apk/repositories 将 #http://mirrors.aliyun.com/alpine/v3.23/community 注释去掉（把“http”前面的井字符号删除即可）。 安装其它必要组件 apk add bash curl util-linux parted e2fsprogs 使用 wipefs 查看磁盘标签，如若类似于以下结果： wipefs -n /dev/vda DEVICE OFFSET TYPE UUID LABEL vda 0x8001 iso9660 2025-12-17-07-03-17-00 alpine-virt 3.23.2 x86_64 vda 0x1fe dos vda 0x200 gpt 说明 gpt 分区表、iso 标签的存在，会影响到后续 grub 的配置与引导，需要清除： 确认 /boot 分区正在被挂载在本机硬盘 vda 上 mount | grep -E '/boot|vda' || true /dev/vda3 on / type ext4 (rw,relatime) /dev/vda1 on /boot type ext4 (rw,relatime) 如果第 6 步确认为是（非空），卸载 /boot 分区，以免被干扰 umount /boot 确认 vda1 的起始位置（可选） parted -s /dev/vda unit KiB print Model: Virtio Block Device (virtblk) Disk /dev/vda: 10485760kiB Sector size (logical/physical): 512B/512B Partition Table: msdos Disk Flags: Number Start End Size Type File system Flags 1 1024kiB 308224kiB 307200kiB primary ext4 boot 2 308224kiB 1199104kiB 890880kiB primary linux-swap(v1) swap 3 1199104kiB 10485760kiB 9286656kiB primary ext4 因为第 10 步会清除 32 KiB - 1024 KiB 区间，若 vda1 起始扇区小于 1024 KiB，会直接使 vda1 分区数据遭到破坏。 用 wipefs 清除 iso、gpt 标签的做法更为规范，但经常会遇到设备忙的问题（wipefs: error: /dev/vda: probing initialization failed: Resource busy），如果执行本步清除命令不成功，直接跳转到第 10、11 步，继续用 dd 命令强制清除 确认 swap 挂载状态，如果为空，不需要卸载：swapon --show || true NAME TYPE SIZE USED PRIO /dev/vda2 partition 870M 0B -2 卸载 swap：swapoff -a再次确认 swap 挂载状态，如果卸载失败，请根据报错自行解决权限等问题：swapon --show || true 清除硬盘 vda 上的 iso 9660 标签：wipefs -a -t iso9660 -f /dev/vda 清除硬盘 vda 上的 gpt 标签：wipefs -a -t gpt -f /dev/vda wipefs 成功后，再次：wipefs -n /dev/vda 结果应该不再出现 iso 9660 / gpt，若二者仍然存在，或 wipefs 报错/忙，再按照第 10、11 步 dd。 确认系统盘第一个分区起点大于 1024KiB（见第8步），否则不要执行本条 dd 命令 alpine linux virt ISO 的 iso 9660 签名 / 卷描述符，会落在磁盘早期区域（非 0 扇区），而本机 vda1 从 1 MiB 对齐开始，所以清除 32 KiB - 1 MiB 区块，可以抹掉 iso 签名且不损伤分区内其他数据，以 10GB ESSD 硬盘，以上 wipefs 查询结果为例，清除“ISO 9660 签名区域”，32 KB - 1 MB，安全区：dd if=/dev/zero of=/dev/vda bs=1K seek=32 count=992 conv=notrunc 992+0 records in 992+0 records out 1015808 bytes (992.0KB) copied, 0.174056 seconds, 5.6MB/s sync 清除“GPT 头/表”，LBA1 开始的 33 个扇区，不要动 MBR 的 LBA0 dd if=/dev/zero of=/dev/vda bs=512 seek=1 count=33 conv=notrunc 33+0 records in 33+0 records out 16896 bytes (16.5KB) copied, 0.000082 seconds, 196.5MB/s sync 重新挂载 /boot 分区 “vda1”在其他环境可能有所不同，需要用“lsblk”事先确认：lsblk -o NAME,SIZE,FSTYPE,MOUNTPOINT NAME SIZE FSTYPE MOUNTPOINT vda 10G ├─vda1 300M ext4 ├─vda2 870M swap └─vda3 8.9G ext4 / 再根据实际硬盘名挂载 /boot：mount /dev/vda1 /boot 验证 gpt、iso 标签，是否已被清除 wipefs -n /dev/vda DEVICE OFFSET TYPE UUID LABEL vda 0x1fe dos 如果在硬盘末尾 33 个扇区，还发现了残留的 gpt 分区标签，则需要继续清理 SECTORS=$(cat /sys/block/vda/size) dd if=/dev/zero of=/dev/vda bs=512 seek=$((SECTORS-33)) count=33 conv=notrunc sync 确认清除后，参考 alpine linux 官方指南，安装并配置 grub： 安装 grub，grub-bios 组件 apk add grub grub-bios 用 lsblk 确认自己的系统盘符名，阿里云 ECS 系统盘默认为“vda”（如果不是，请自行修改） lsblk -f NAME FSTYPE FSVER LABEL UUID FSAVAIL FSUSE% MOUNTPOINTS vda ├─vda1 ext4 53a935b3-8725-4c1e-9d2d-2b685d3ab97f 225.3M 10% /boot ├─vda2 swap 05554c58-807d-420f-ad8a-cbf054f32faf └─vda3 ext4 3c9fca1f-4161-4a64-a94b-03da3fe216d5 8G 1% / 然后以 BIOS 模式，将 MBR 与 GRUB 二进制文件安装到系统盘：grub-install --recheck /dev/vda 显示以下结果，说明安装成功：Installing for i386-pc platform. Installation finished. No error reported. 如果 grub-install 在执行后，报以下错误，说明 gpt、iso 等标签未被清除干净，需要重新运行步骤 5 确认：grub-install: warning: Attempting to install GRUB to a disk with multiple partition labels. This is not supported yet.. grub-install: warning: Embedding is not possible. GRUB can only be installed in this setup by using blocklists. However, blocklists are UNRELIABLE and their use is discouraged.. grub-install: error: will not proceed with blocklists. 以上各类错误发生的原因，是 alpine 的 virt 版 ISO，为了保证能以光盘模式发行，被制成可引导启动的镜像的同时，还可以被安装在硬盘上启动，以及在 BIOS 与 UEFI 两种固件的机型上兼容运行，采取了 isohybrid（混合引导）模式，它自带： iso 9660（光盘文件系统签名） dos（MBR 签名，0x55AA） gpt（GPT 头/表签名） 然而用户在安装并配置 grub 时，grub 认为，硬盘“/dev/vda”上，同时存在不止一种分区表签名（比如 MBR(msdos) + 残留的 GPT 头/尾），所以提示：disk with multiple partition labels 然后直接禁止 embedding（嵌入 core.img），只能退回到 blocklists，而 grub2 默认拒绝 blocklists → will not proceed with blocklists，这就会触发 grub 的写保护逻辑，导致配置失败。 读取硬盘 vda 的第一个扇区，并以 16 进制的形式，输出最后部分，确认 MBR 扇区结尾为 55 aa（MBR 签名），能否被成功引导，以第 21 步重启出现 grub 菜单为准 dd if=/dev/vda bs=512 count=1 | hexdump -C | tail 1+0 records in 1+0 records out 512 bytes (512B) copied, 0.000021 seconds, 23.3MB/s 00000170 be 95 7d e8 34 00 be 9a 7d e8 2e 00 cd 18 eb fe |..}.4...}.......| 00000180 47 52 55 42 20 00 47 65 6f 6d 00 48 61 72 64 20 |GRUB .Geom.Hard | 00000190 44 69 73 6b 00 52 65 61 64 00 20 45 72 72 6f 72 |Disk.Read. Error| 000001a0 0d 0a 00 bb 01 00 b4 0e cd 10 ac 3c 00 75 f4 c3 |...........<.u..| 000001b0 00 00 00 00 00 00 00 00 8e 55 75 6a 00 00 80 00 |.........Uuj....| 000001c0 21 02 83 08 b8 63 00 08 00 00 00 60 09 00 00 08 |!....c.....`....| 000001d0 b9 63 82 0f ff ff 00 68 09 00 00 30 1b 00 00 0f |.c.....h...0....| 000001e0 ff ff 83 0f ff ff 00 98 24 00 00 68 1b 01 00 00 |........$..h....| 000001f0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 55 aa |..............U.| 00000200 编辑“/etc/default/grub”文件，在最后一行加上一条用于启动当前系统的命令行： vim /etc/default/grub GRUB_CMDLINE_LINUX_DEFAULT="quiet rootfstype=ext4" 如遇极少数环境下，initramfs 未包含 virtio 模块，才考虑追加参数“modules=virtio,virtio_pci,virtio_blk”。 自动生成配置文件并使grub生效 grub-mkconfig -o /boot/grub/grub.cfg Generating grub configuration file ... Found linux image: /boot/vmlinuz-virt Found initrd image: /boot/initramfs-virt Warning: os-prober will not be executed to detect other bootable partitions. Systems on them will not be added to the GRUB boot configuration. Check GRUB_DISABLE_OS_PROBER documentation entry. done 出现“Warning”提示是，grub 不会自动扫描并添加其它系统（如 Windows、其它 Linux 发行版）到其引导项，单系统环境下，该问题视同可被忽略。 重启系统，在 VNC 下可看出，alpine linux 已由 grub 引导启动。 已确认 VNC 显示 grub 菜单并进入 alpine，删除 alpine linux virt 默认的 syslinux 引导工具。 apk del syslinux grub 引导问题解决，再次进入 alpine，用一键脚本重装其他系统就没问题了，alpine linux 虽然也折腾不少了，但果然还是没有 Debian 顺手。 重装成 Debian 13。 下载：wget --no-check-certificate -qO InstallNET.sh 'https://raw.githubusercontent.com/leitbogioro/Tools/master/Linux_reinstall/InstallNET.sh' && chmod a+x InstallNET.sh 安装 Debian 13，推荐使用来自阿里云内网“aliyuncs.com”域名的源，该源不对外提供服务，外界同样无法访问，但阿里云任何地域机器都可以访问当地的内网源，延迟、传输速度对阿里云机器来说，可谓是最爽的，指定为其分配 512 MB 虚拟内存（-swap '512'），强制关闭安装云内核（--cloudkernel "0"）、开启 bbr（--bbr）、开启 ssh 登录时类 Ubuntu 的系统状态显示（--motd）、强制将 DNS 修改成 Cloudflare 与 Google，不走云服务商自己提供的 DNS 配置（--setdns），以免 DNS 解析被污染。bash InstallNET.sh -debian 13 -port "端口自定，默认跟随原系统" -pwd '密码自定，默认 LeitboGi0ro' -mirror "http://mirrors.cloud.aliyuncs.com/debian/" -swap '512' --cloudkernel "0" --bbr --motd --setdns
更新（2026.01.10）： 重要提示：从自制镜像中读取到的 alpine virt iso 救援系统，在 VNC 执行 setup-alpine，将正式系统写入到硬盘后，该临时系统还运行在内存中，必须要重启！必须要重启！必须要重启！重启后进入到的 alpine 系统，才是从系统硬盘中读取的正式系统，才可以进行设置 DNS、配置源、清除硬盘标签、执行脚本重装等后续工作。 援引 & 致谢： 使用阿里云CDT 享受每月200G/4元高速流量 后续高阶玩法，支持用脚本重装，请移步： 【全网首发】极限低成本吃满阿里云 CDT 200G 高速流量：Alpine 作为救援系统，一键重装 Debian（修复 GRUB / 清理 isohybrid 残留全流程） 援引源网站证书于 2026 年 1 月 4 日失效，且网站开启了 HSTS，无法为此网站添加例外以访问，web archive 里也没有存档，我保存了一份在本地，本帖对该篇教程的过时内容和不完善内容进行一些修订，该教程同样适合阿里云国际站。原理：阿里云香港最近表现不错，但新手轻量优惠不可选择香港，只能正价购买香港轻量，持有成本较高，所以我们可以利用阿里云（含阿里云国际版）每个账号免费赠送的 200 GB CDT（云数据传输）流量，配合配置最低的 ECS 实例，达到低成本搭乘阿里云香港网络快线的方法。CDT公网流量免费额度提升至220 GB/月 产品： CDT 公网流量 免费额度与适用地域： 免费额度为 220 GB/月，其中： 中国内地地域：20 GB/月 非中国内地地域：200 GB/月 线路类型： BGP（多线） 正文：本文将介绍如何开启 CDT + 创建阿里云抢占式实例 + 保活，实现月付最低 4 元，享受 200G 单向出网高速流量的方法。零、开通阿里云 CDT 功能在控制台首页搜索框，直接输入“CDT”，自动弹出“控制台 > 云数据传输”选项，点击；或直接访问：https://cdt.console.aliyun.com/overview （阿里云国际站：https://cdt.console.alibabacloud.com/overview ），进入 CDT 工作台。确认当前账户下的所有 CDT 子功能，如图示开通，如果还没有开通，选择未开通子项，点击“一键升级”：一、开通阿里云 OSS 并上传 alpine 镜像 搜索栏搜索 oss 并开通： 上传镜像至 oss 2.1 点击管理控制台，创建 bucket，地域切记选择香港：2.2 创建成功后，进入 bucket，上传所需 apline 镜像：https://dl-cdn.alpinelinux.org/alpine/v3.23/releases/x86_64/alpine-virt-3.23.2-x86_64.iso 点击上传文件，上传刚刚下载好的 alpine 镜像:2.3 保存上传好的镜像链接，下一步要用：二、创建系统镜像 导入镜像： 点击 https://ecs.console.aliyun.com/image/region/cn-hongkong （阿里云国际站：https://ecs.console.alibabacloud.com/image/region/cn-hongkong ），导入刚刚上传到 oss 的 alpine 镜像：点击下一步：“镜像检测 → 导入后执行检测”最好不勾：“云盘配置 → 配置云盘属性”勾选，alpine virt ISO 镜像体积很小，虽然原文里给 1GB 空间启动足够，但保险起见，还是建议给 2GB 以上，除非你执意只给 ECS 配置 1GB 的硬盘，但安装许多系统会受限制（系统本体、应用、日志等）。后面创建机器时可选的硬盘容量，必须等于或大于导入镜像步骤设置的云盘容量。耐心等待创建完成：三、创建抢占式实例在 https://ecs.console.aliyun.com/server/region/cn-hongkong#/ （阿里云国际站：https://ecs.console.alibabacloud.com/server/region/cn-hongkong#/ ）创建抢占式实例：规格搜索：ecs.e-c4m1.large 选中该“经济型”： 实例使用时长：无确定使用时长（否则按默认只设置 1 小时，1 小时后被删机）； 单台实例上限价格：使用自动出价，香港不同的区价格不一样，而且随资源变化随时浮动，图示价格仅供参考； 实例中断模式：节省停机（必须选这个，否则还是被删机）； 区域香港 B、C、D 区任意，首次创建时，会自动配置好对应地区的 VPC，不需要手动配置； 镜像选我们刚才创建的自定义的 alpine； 系统盘容量看自己选择，ESSD Entry 单 GB 价格便宜，但最低要配置 10 GB，极限容量下，价格比 ESSD 云盘贵，推荐 5 - 8 GB 的 ESSD 云盘或 10 GB 的 ESSD Entry 硬盘，1 - 2 GB 的那种玩法有点极限。 先暂不分配 IPv4 地址，原因是该抢占式实例属于可被随时停机的那种，如果有大户开机，占据了某可用区（香港：B、C、D 区任意）的大量资源，这些抢占式实例被停机后，再次启动时，创建时自动分配的 IPv4 地址会被释放，所以我们需要使用 EIP 来使这台机器的 IPv4 地址固定；安全组、防火墙等自行做入网、出网设置，全开就行；如果对 IPv6 的使用没有强需求，建议不要为实例分配 IPv6 地址，阿里云对 IPv6 的支持仍然不是很好。确认配置无误，开氪：四、创建 EIP（弹性公网 IP）EIP 纯持有是持续扣费的，只要绑定到实例后，就不扣费了，后期机器如果不要了删除，记得把闲置的 EIP 也删掉，否则会产生额外费用。 进入 EIP 功能区： 访问：https://vpc.console.aliyun.com/eip/cn-hongkong/eips （阿里云国际：https://vpc.console.alibabacloud.com/eip/cn-hongkong/eips ）创建： 确认配置，点击购买： 付费模式：按量付费； 地域和可用区：中国香港； 线路类型：BGP(多线)，BGP 多线精品不享受 200GB CDT 免费额度； 网络类型：公网； 安全防护：默认； 计费模式：按 CDT 计费； 带宽峰值：ecs.e-c4m1.large 的口子为 200 Mbps，拉满。 绑定实例： 访问：https://ecs.console.aliyun.com/server/region/cn-hongkong （阿里云国际：https://ecs.console.alibabacloud.com/server/region/cn-hongkong ），操作 → 三个点 → 绑定弹性公网 IP： 返回弹性公网 IP，创建加入共享带宽，可继续加大出网带宽量： 计费方式：按主流量（入出取大）； 计费模式：按 CDT 计费； 带宽：根据需求自选，拉太大了会增加流量的消耗速度。在阿里云国际版做过测试，如果下单失败，显示：因安全问题，此次下单被终止，Request ID: 一串 UUID。需要访问：https://account.alibabacloud.com/kyc/index#/kyc 做 KYC 验证，它的审核特别严格，且阿里云国际版注册时，仅支持选择海外地区，根据接码手机号区号，确定账号主体注册区域，如果没有当地合法的长期居留身份，这一步基本无法通过，只能退而求其次，使用实例自带的 200 Mbps 的口子。现在就成为 2 Gbps 口子的服务器了。五、安装系统 安装 首次需要登录 VNC，输入 root，密码为空，来到 Localhost#: 状态，输入setup-alpine进行首次安装，这个跟平时我们安装软件差不多的，一路回车，下一步下一步基本就可以了，其中有几步需要修改一下的，我在图片上标出来。这就配置好网络了，阿里云使用 DHCP，不需要手动配置网络。这样配置好用户名和密码及时区，代理跳过（如果只按原文图示直接按“49”，有可能会连接到一个速度极慢的源，因为这个镜像列表是实时更新的，截止我做测试时，阿里云的镜像源序号是“44”，这个序号未来还会根据该列表的更新而随时变化，切勿刻舟求剑，需要先按“s show mirrorlist”显示镜像源列表，然后选择来自 https://mirrors.aliyun.com/alpine/ 的源）。启用 root 用户，并使用密码方式验证登录。 配置磁盘、分区、格式化 这一步会提示 No disks available，Try boot media /media/vda ? 意思没有找到可用有磁盘，是否尝试安装到vda云盘上，改y安装完成后reboot重启，首次安装向导就完成了。重要提示：从自制镜像中读取到的 alpine virt iso 救援系统，在 VNC 执行 setup-alpine，将正式系统写入到硬盘后，该临时系统还运行在内存中，必须要重启！必须要重启！必须要重启！重启后进入到的 alpine 系统，才是从系统硬盘中读取的正式系统，才可以进行设置 DNS、配置源、清除硬盘标签、执行脚本重装等后续工作。 修改 DNS 由于 alpine 系统还未联网，所以这一步还是需要在 VNC 中操作，如果不设置 DNS，只能 ping 通 IP 地址，无法 ping 通域名。输入setup-dnsDNS domain name:nameserverDNS 地址随意，推荐：1.1.1.1 8.8.8.8当系统的网络连接功能完全正常后，便可使用 Xshell 等 ssh 工具进行远程连接。 安装 curl，vim 先更新一下软件源：apk update安装组件：apk add curl vim其它应用也是类似。 添加额外源（可选） 仓库配置路径：/etc/apk/repositories打开仓库配置文件：vim /etc/apk/repositories将社区源开头注释去掉：http://mirrors.aliyun.com/alpine/v3.23/main # 默认配置，主要的源 http://mirrors.aliyun.com/alpine/v3.23/community # 社区源，默认未开启，去掉前面#号 添加 edge 源，拥有很多第三方应用，旧版 alpine 配置 edge 源，安装软件时，会产生很多依赖问题，不推荐：http://mirrors.aliyun.com/alpine/edge/community http://mirrors.aliyun.com/alpine/edge/testing 将仓库配置文件保存后，再次更新源：apk update已经开好了，剩下的玩法大伙自己发掘吧，现在可以把 oss 与镜像删除了，防止额外扣费。六、保活服务器需要使用阿里云 sdk。 先创建一个用户并赋予权限 访问：https://ram.console.aliyun.com/users （阿里云国际版：https://ram.console.alibabacloud.com/users）记得保存 AccessKey ID、AccessKey Secret，后面需要用到。 为刚创建的用户增加授权 新建修改下列脚本，安装必要依赖，设定每分钟执行。切记在另外的机器上设置，不要在阿里云抢占式实例自己上运行。使用 crontab 设置为每分钟执行一次。# -*- coding: utf-8 -*- from aliyunsdkcore.client import AcsClient from aliyunsdkcore.request import CommonRequest from aliyunsdkecs.request.v20140526 import StartInstancesRequest, StopInstancesRequest, DescribeInstancesRequest import json import sys import logging # pip install aliyun-python-sdk-core aliyun-python-sdk-ecs # ================== 1. 配置日志 ================== logging.basicConfig( level=logging.INFO, format="%(asctime)s - %(levelname)s - %(message)s", stream=sys.stdout ) logger = logging.getLogger(__name__) # ================== 2. 配置阿里云凭证和ECS实例信息 ================== ACCESS_KEY_ID = 'LTAIxxxxxxx' # 您的AccessKey ID ACCESS_KEY_SECRET = 'xxxxxxxxxx' # 您的AccessKey Secret REGION_ID = 'cn-hongkong' # 区域ID ECS_INSTANCE_ID = 'i-xxxxxxxxx' # 您要控制的ECS实例ID # 流量阈值 (GB) TRAFFIC_THRESHOLD_GB = 180 # ================== 3. 初始化客户端 ================== try: client = AcsClient(ACCESS_KEY_ID, ACCESS_KEY_SECRET, REGION_ID) logger.info("AcsClient initialized successfully.") except Exception as e: logger.error(f"Failed to initialize AcsClient: {e}") sys.exit(1) # ================== 4. 查询当前总流量 ================== def get_total_traffic_gb(client): request = CommonRequest() request.set_domain('cdt.aliyuncs.com') request.set_version('2021-08-13') request.set_action_name('ListCdtInternetTraffic') request.set_method('POST') try: response = client.do_action_with_exception(request) response_json = json.loads(response.decode('utf-8')) total_bytes = sum(d.get('Traffic', 0) for d in response_json.get('TrafficDetails', [])) total_gb = total_bytes / (1024 ** 3) logger.info(f"当前总互联网流量: {total_gb:.2f} GB") return total_gb except Exception as e: logger.error(f"获取CDT流量失败: {e}") sys.exit(1) # ================== 5. 查询ECS实例状态 ================== def get_ecs_status(client, instance_id): try: request = DescribeInstancesRequest.DescribeInstancesRequest() request.set_InstanceIds([instance_id]) response = client.do_action_with_exception(request) response_json = json.loads(response.decode('utf-8')) instances = response_json.get("Instances", {}).get("Instance", []) if not instances: logger.error("未找到该ECS实例信息。") return None status = instances[0].get("Status") logger.info(f"ECS实例 {instance_id} 当前状态: {status}") return status except Exception as e: logger.error(f"获取ECS实例状态失败: {e}") return None # ================== 6. 启动ECS实例 ================== def ecs_start(client, instance_id): status = get_ecs_status(client, instance_id) if status == "Running": logger.info(f"ECS实例 {instance_id} 已经是运行状态，无需启动。") return try: request = StartInstancesRequest.StartInstancesRequest() request.set_InstanceIds([instance_id]) request.set_accept_format('json') response = client.do_action_with_exception(request) logger.info(f"ECS启动响应: {response.decode('utf-8')}") except Exception as e: logger.error(f"启动ECS实例失败: {e}") # ================== 7. 停止ECS实例 ================== def ecs_stop(client, instance_id): status = get_ecs_status(client, instance_id) if status == "Stopped": logger.info(f"ECS实例 {instance_id} 已经是停止状态，无需再次停止。") return try: request = StopInstancesRequest.StopInstancesRequest() request.set_InstanceIds([instance_id]) request.set_ForceStop(False) request.set_accept_format('json') response = client.do_action_with_exception(request) logger.info(f"ECS停止响应: {response.decode('utf-8')}") except Exception as e: logger.error(f"停止ECS实例失败: {e}") # ================== 8. 主流程 ================== def main(): total_gb = get_total_traffic_gb(client) if total_gb < TRAFFIC_THRESHOLD_GB: logger.info(f"流量 {total_gb:.2f} GB < 阈值 {TRAFFIC_THRESHOLD_GB} GB，尝试启动 ECS") ecs_start(client, ECS_INSTANCE_ID) else: logger.info(f"流量 {total_gb:.2f} GB ≥ 阈值 {TRAFFIC_THRESHOLD_GB} GB，尝试停止 ECS") ecs_stop(client, ECS_INSTANCE_ID) logger.info("脚本执行完毕。") if __name__ == "__main__": main()
转发脚本记录#!/bin/bash # 更新系统并安装依赖 sudo apt update sudo apt install -y iptables iptables-persistent # 开启内核转发 echo "net.ipv4.ip_forward=1" | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 加载连接追踪模块 sudo modprobe nf_conntrack # 配置全端口转发（TCP/UDP） sudo iptables -t nat -A PREROUTING -p tcp -j DNAT --to-destination 专线入口地址 sudo iptables -t nat -A PREROUTING -p udp -j DNAT --to-destination 专线入口地址 # 转发ICMP请求 sudo iptables -t nat -A PREROUTING -p icmp --icmp-type any -j DNAT --to-destination 专线入口地址 # 允许转发到目标IP的所有流量 sudo iptables -A FORWARD -d 专线入口地址 -j ACCEPT # 配置MASQUERADE（源地址伪装） sudo iptables -t nat -A POSTROUTING -p tcp -d 专线入口地址 -j MASQUERADE sudo iptables -t nat -A POSTROUTING -p udp -d 专线入口地址 -j MASQUERADE sudo iptables -t nat -A POSTROUTING -p icmp -d 专线入口地址 -j MASQUERADE # 抗DDoS防护（限制SYN和ICMP） sudo iptables -A FORWARD -p tcp --syn -m limit --limit 1/s --limit-burst 3 -j ACCEPT sudo iptables -A FORWARD -p icmp --icmp-type echo-request -m limit --limit 1/s -j ACCEPT # 提升UDP连接数限制 echo "net.netfilter.nf_conntrack_max=655360" | sudo tee -a /etc/sysctl.conf sudo sysctl -p # 保存规则 sudo iptables-save | sudo tee /etc/iptables/rules.v4 echo "配置完成！"
前言之前在github上找来的，本来挺好用的，但是后来github的作者修改了脚本，搞的有些不好用，可能是没有修复BUG什么的，反正之前下的脚本我就暂存一份在自己博客，免得以后丢了！顺便说下，我也不知道是哪个作者了！用法复制以下代码，保存为templates.sh即可，拉到PVE根目录，给与执行权限，然后./templates.sh就可以操作了，爱选哪个选哪个！还有几个脚本是一次性全部下载，我也放上去！交互式的脚本如下#!/bin/bash # 函数：提示用户输入网络接口和存储 prompt_for_network_and_storage() { echo -n "请输入网络接口（例如 vmbr0，默认为 vmbr0）：" read -r vmbr if [ -z "$vmbr" ]; then vmbr="vmbr0" fi echo -n "请输入存储名称（例如 local，默认为 local）：" read -r storage if [ -z "$storage" ]; then storage="local" fi } # 函数：显示发行版选项菜单（仅在交互模式下使用） show_distro_menu() { echo "=====================================" echo "欢迎使用 Proxmox VE 虚拟机模板创建脚本" echo "=====================================" echo "请选择要创建的发行版：" echo "1. Debian 12" echo "2. Debian 11" echo "3. CentOS 9 Stream" echo "4. CentOS 8 Stream" echo "5. Ubuntu 22.04" echo "6. Ubuntu 24.04" echo "7. AlmaLinux 8" echo "8. AlmaLinux 9" echo "9. Rocky Linux 8" echo "10. Rocky Linux 9" echo -n "请输入选项 (1-10)：" read -r choice case $choice in 1) distro="debian12" image_url="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2" image_file="debian-12-generic-amd64.qcow2" vm_name="Debian-12" ;; 2) distro="debian11" image_url="https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2" image_file="debian-11-generic-amd64.qcow2" vm_name="Debian-11" ;; 3) distro="centos9" image_url="https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2" image_file="CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2" vm_name="CentOS-9" ;; 4) distro="centos8" image_url="https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2" image_file="CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2" vm_name="CentOS-8" ;; 5) distro="ubuntu22" image_url="https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" image_file="jammy-server-cloudimg-amd64.img" vm_name="Ubuntu-22" ;; 6) distro="ubuntu24" image_url="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" image_file="noble-server-cloudimg-amd64.img" vm_name="Ubuntu-24" ;; 7) distro="alma8" image_url="https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/AlmaLinux-8-GenericCloud-latest.x86_64.qcow2" image_file="AlmaLinux-8-GenericCloud-latest.x86_64.qcow2" vm_name="AlmaLinux-8" ;; 8) distro="alma9" image_url="https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" image_file="AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" vm_name="AlmaLinux-9" ;; 9) distro="rocky8" image_url="https://download.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud.latest.x86_64.qcow2" image_file="Rocky-8-GenericCloud.latest.x86_64.qcow2" vm_name="Rocky-8" ;; 10) distro="rocky9" image_url="https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" image_file="Rocky-9-GenericCloud.latest.x86_64.qcow2" vm_name="Rocky-9" ;; *) echo "无效选项，请选择 1-10 之间的数字。" exit 1 ;; esac # 提示用户输入 VMID echo -n "请输入 VMID（例如 8000）：" read -r vmid if ! [[ "$vmid" =~ ^[0-9]+$ ]]; then echo "VMID 必须是数字。" exit 1 fi } # 函数：通过参数设置发行版和 VMID（非交互模式） set_distro_and_vmid() { local choice=$1 local input_vmid=$2 case $choice in 1) distro="debian12" image_url="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2" image_file="debian-12-generic-amd64.qcow2" vm_name="Debian-12" ;; 2) distro="debian11" image_url="https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2" image_file="debian-11-generic-amd64.qcow2" vm_name="Debian-11" ;; 3) distro="centos9" image_url="https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2" image_file="CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2" vm_name="CentOS-9" ;; 4) distro="centos8" image_url="https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2" image_file="CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2" vm_name="CentOS-8" ;; 5) distro="ubuntu22" image_url="https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" image_file="jammy-server-cloudimg-amd64.img" vm_name="Ubuntu-22" ;; 6) distro="ubuntu24" image_url="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" image_file="noble-server-cloudimg-amd64.img" vm_name="Ubuntu-24" ;; 7) distro="alma8" image_url="https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/AlmaLinux-8-GenericCloud-latest.x86_64.qcow2" image_file="AlmaLinux-8-GenericCloud-latest.x86_64.qcow2" vm_name="AlmaLinux-8" ;; 8) distro="alma9" image_url="https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" image_file="AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" vm_name="AlmaLinux-9" ;; 9) distro="rocky8" image_url="https://download.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud.latest.x86_64.qcow2" image_file="Rocky-8-GenericCloud.latest.x86_64.qcow2" vm_name="Rocky-8" ;; 10) distro="rocky9" image_url="https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" image_file="Rocky-9-GenericCloud.latest.x86_64.qcow2" vm_name="Rocky-9" ;; *) echo "无效选项：$choice，请选择 1-10 之间的数字。" exit 1 ;; esac vmid=$input_vmid if ! [[ "$vmid" =~ ^[0-9]+$ ]]; then echo "VMID 必须是数字：$vmid" exit 1 fi } # 函数：检查并销毁已存在的虚拟机（带确认） destroy_existing_vm() { local vmid=$1 if qm status $vmid >/dev/null 2>&1; then echo "检测到 VMID $vmid 已存在，是否销毁？（输入 Y/y 确认，其他键取消）" read -r confirm if "$confirm" != "Y" && "$confirm" != "y" ; then echo "用户取消销毁操作，脚本退出。" exit 1 fi echo "正在销毁 VMID $vmid..." # 停止虚拟机（如果正在运行） qm stop $vmid 2>/dev/null # 销毁虚拟机 qm destroy $vmid --destroy-unreferenced-disks 1 --purge 1 if [ $? -ne 0 ]; then echo "销毁虚拟机失败：VMID $vmid" exit 1 fi echo "已销毁 VMID $vmid 及其未引用磁盘和作业配置。" fi } # 函数：下载镜像 download_image() { local url=$1 local file=$2 echo "正在下载 $file ..." wget -O /tmp/$file $url if [ $? -ne 0 ]; then echo "下载失败：$url" echo "请检查网络连接或镜像地址是否有效。" exit 1 fi } # 函数：创建虚拟机 create_vm() { local vmid=$1 local vm_name=$2 local vmbr=$3 echo "正在创建虚拟机 $vm_name (VMID: $vmid)..." # 创建虚拟机时不添加默认硬盘，使用用户指定的网络接口 qm create $vmid --memory 2048 --core 2 --name $vm_name --net0 virtio,bridge=$vmbr --ide0 none if [ $? -ne 0 ]; then echo "创建虚拟机失败：VMID $vmid" exit 1 fi } # 函数：导入磁盘 import_disk() { local vmid=$1 local image_file=$2 local storage=$3 # 导入磁盘到用户指定的存储 echo "正在导入磁盘 /tmp/$image_file 到 $storage 存储..." qm importdisk $vmid /tmp/$image_file $storage --format qcow2 if [ $? -ne 0 ]; then echo "导入磁盘失败：$image_file" exit 1 fi # 检查导入的磁盘文件是否存在（路径可能因存储类型不同而变化） if [ ! -f "/var/lib/vz/images/$vmid/vm-$vmid-disk-0.qcow2" ]; then echo "警告：未在 /var/lib/vz/images/$vmid/ 找到磁盘文件，可能是存储路径不同，请手动检查。" else echo "磁盘文件 /var/lib/vz/images/$vmid/vm-$vmid-disk-0.qcow2 已成功生成。" fi } # 函数：配置虚拟机 configure_vm() { local vmid=$1 local storage=$2 # 设置 SCSI 控制器并挂载导入的磁盘 echo "正在挂载磁盘 $storage:$vmid/vm-$vmid-disk-0.qcow2 到 scsi0..." qm set $vmid --scsihw virtio-scsi-pci --scsi0 $storage:$vmid/vm-$vmid-disk-0.qcow2 if [ $? -ne 0 ]; then echo "挂载磁盘到 scsi0 失败：VMID $vmid" # 打印存储内容以供调试 echo "当前 $storage 存储内容：" ls -lh /var/lib/vz/images/$vmid/ 2>/dev/null || echo "无法列出存储内容，可能是存储路径不同。" exit 1 fi # 配置 CloudInit、启动顺序等 qm set $vmid --ide2 $storage:cloudinit qm set $vmid --boot c --bootdisk scsi0 qm set $vmid --serial0 socket --vga serial0 } # 函数：将虚拟机转换为模板 convert_to_template() { local vmid=$1 echo "正在将 VMID $vmid 转换为模板..." qm template $vmid if [ $? -ne 0 ]; then echo "转换为模板失败：VMID $vmid" exit 1 fi } # 主函数 main() { # 如果提供了参数（发行版选项和 VMID），则使用参数运行 if [ $# -eq 2 ]; then set_distro_and_vmid "$1" "$2" else # 否则进入交互模式 show_distro_menu fi # 提示用户输入网络接口和存储 prompt_for_network_and_storage # 检查并销毁已存在的虚拟机 destroy_existing_vm $vmid # 下载镜像 download_image $image_url $image_file # 创建虚拟机 create_vm $vmid $vm_name $vmbr # 导入磁盘 import_disk $vmid $image_file $storage # 配置虚拟机 configure_vm $vmid $storage # 转换为模板 convert_to_template $vmid # 清理临时文件 rm /tmp/$image_file echo "=====================================" echo "虚拟机模板 $vm_name (VMID: $vmid) 创建并转换为模板完成！" echo "=====================================" } # 运行主函数 main "$@" 全部下载系统模版#!/bin/bash # 函数：提示用户输入网络接口和存储 prompt_for_network_and_storage() { echo -n "请输入网络接口（例如 vmbr0，默认为 vmbr0）：" read -r vmbr if [ -z "$vmbr" ]; then vmbr="vmbr0" fi echo -n "请输入存储名称（例如 local，默认为 local）：" read -r storage if [ -z "$storage" ]; then storage="local" fi } # 函数：设置发行版信息 set_distro_info() { local choice=$1 local input_vmid=$2 case $choice in 1) distro="debian12" image_url="https://cloud.debian.org/images/cloud/bookworm/latest/debian-12-generic-amd64.qcow2" image_file="debian-12-generic-amd64.qcow2" vm_name="Debian-12" ;; 2) distro="debian11" image_url="https://cloud.debian.org/images/cloud/bullseye/latest/debian-11-generic-amd64.qcow2" image_file="debian-11-generic-amd64.qcow2" vm_name="Debian-11" ;; 3) distro="centos9" image_url="https://cloud.centos.org/centos/9-stream/x86_64/images/CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2" image_file="CentOS-Stream-GenericCloud-9-latest.x86_64.qcow2" vm_name="CentOS-9" ;; 4) distro="centos8" image_url="https://cloud.centos.org/centos/8-stream/x86_64/images/CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2" image_file="CentOS-Stream-GenericCloud-8-latest.x86_64.qcow2" vm_name="CentOS-8" ;; 5) distro="ubuntu22" image_url="https://cloud-images.ubuntu.com/jammy/current/jammy-server-cloudimg-amd64.img" image_file="jammy-server-cloudimg-amd64.img" vm_name="Ubuntu-22" ;; 6) distro="ubuntu24" image_url="https://cloud-images.ubuntu.com/noble/current/noble-server-cloudimg-amd64.img" image_file="noble-server-cloudimg-amd64.img" vm_name="Ubuntu-24" ;; 7) distro="alma8" image_url="https://repo.almalinux.org/almalinux/8/cloud/x86_64/images/AlmaLinux-8-GenericCloud-latest.x86_64.qcow2" image_file="AlmaLinux-8-GenericCloud-latest.x86_64.qcow2" vm_name="AlmaLinux-8" ;; 8) distro="alma9" image_url="https://repo.almalinux.org/almalinux/9/cloud/x86_64/images/AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" image_file="AlmaLinux-9-GenericCloud-latest.x86_64.qcow2" vm_name="AlmaLinux-9" ;; 9) distro="rocky8" image_url="https://download.rockylinux.org/pub/rocky/8/images/x86_64/Rocky-8-GenericCloud.latest.x86_64.qcow2" image_file="Rocky-8-GenericCloud.latest.x86_64.qcow2" vm_name="Rocky-8" ;; 10) distro="rocky9" image_url="https://download.rockylinux.org/pub/rocky/9/images/x86_64/Rocky-9-GenericCloud.latest.x86_64.qcow2" image_file="Rocky-9-GenericCloud.latest.x86_64.qcow2" vm_name="Rocky-9" ;; *) echo "无效选项：$choice，请选择 1-10 之间的数字。" exit 1 ;; esac vmid=$input_vmid if ! [[ "$vmid" =~ ^[0-9]+$ ]]; then echo "VMID 必须是数字：$vmid" exit 1 fi } # 函数：检查并销毁已存在的虚拟机（自动确认销毁） destroy_existing_vm() { local vmid=$1 if qm status $vmid >/dev/null 2>&1; then echo "检测到 VMID $vmid 已存在，自动销毁..." # 停止虚拟机（如果正在运行） qm stop $vmid 2>/dev/null # 销毁虚拟机 qm destroy $vmid --destroy-unreferenced-disks 1 --purge 1 if [ $? -ne 0 ]; then echo "销毁虚拟机失败：VMID $vmid" exit 1 fi echo "已销毁 VMID $vmid 及其未引用磁盘和作业配置。" fi } # 函数：下载镜像 download_image() { local url=$1 local file=$2 echo "正在下载 $file ..." wget -O /tmp/$file $url if [ $? -ne 0 ]; then echo "下载失败：$url" echo "请检查网络连接或镜像地址是否有效。" exit 1 fi } # 函数：创建虚拟机 create_vm() { local vmid=$1 local vm_name=$2 local vmbr=$3 echo "正在创建虚拟机 $vm_name (VMID: $vmid)..." # 创建虚拟机时不添加默认硬盘，使用用户指定的网络接口 qm create $vmid --memory 2048 --core 2 --name $vm_name --net0 virtio,bridge=$vmbr --ide0 none if [ $? -ne 0 ]; then echo "创建虚拟机失败：VMID $vmid" exit 1 fi } # 函数：导入磁盘 import_disk() { local vmid=$1 local image_file=$2 local storage=$3 # 导入磁盘到用户指定的存储 echo "正在导入磁盘 /tmp/$image_file 到 $storage 存储..." qm importdisk $vmid /tmp/$image_file $storage --format qcow2 if [ $? -ne 0 ]; then echo "导入磁盘失败：$image_file" exit 1 fi # 检查导入的磁盘文件是否存在（路径可能因存储类型不同而变化） if [ ! -f "/var/lib/vz/images/$vmid/vm-$vmid-disk-0.qcow2" ]; then echo "警告：未在 /var/lib/vz/images/$vmid/ 找到磁盘文件，可能是存储路径不同，请手动检查。" else echo "磁盘文件 /var/lib/vz/images/$vmid/vm-$vmid-disk-0.qcow2 已成功生成。" fi } # 函数：配置虚拟机 configure_vm() { local vmid=$1 local storage=$2 # 设置 SCSI 控制器并挂载导入的磁盘 echo "正在挂载磁盘 $storage:$vmid/vm-$vmid-disk-0.qcow2 到 scsi0..." qm set $vmid --scsihw virtio-scsi-pci --scsi0 $storage:$vmid/vm-$vmid-disk-0.qcow2 if [ $? -ne 0 ]; then echo "挂载磁盘到 scsi0 失败：VMID $vmid" # 打印存储内容以供调试 echo "当前 $storage 存储内容：" ls -lh /var/lib/vz/images/$vmid/ 2>/dev/null || echo "无法列出存储内容，可能是存储路径不同。" exit 1 fi # 配置 CloudInit、启动顺序等 qm set $vmid --ide2 $storage:cloudinit qm set $vmid --boot c --bootdisk scsi0 qm set $vmid --serial0 socket --vga serial0 } # 函数：将虚拟机转换为模板 convert_to_template() { local vmid=$1 echo "正在将 VMID $vmid 转换为模板..." qm template $vmid if [ $? -ne 0 ]; then echo "转换为模板失败：VMID $vmid" exit 1 fi } # 函数：创建单个模板 create_template() { local distro_option=$1 local vmid=$2 local vmbr=$3 local storage=$4 # 设置发行版信息 set_distro_info $distro_option $vmid # 检查并销毁已存在的虚拟机 destroy_existing_vm $vmid # 下载镜像 download_image $image_url $image_file # 创建虚拟机 create_vm $vmid $vm_name $vmbr # 导入磁盘 import_disk $vmid $image_file $storage # 配置虚拟机 configure_vm $vmid $storage # 转换为模板 convert_to_template $vmid # 清理临时文件 rm /tmp/$image_file echo "=====================================" echo "虚拟机模板 $vm_name (VMID: $vmid) 创建并转换为模板完成！" echo "=====================================" } # 函数：自动创建所有模板 create_all_templates() { local start_vmid=8000 local distro_count=10 # 总共有 10 个发行版 local current_vmid=$start_vmid # 发行版名称（仅用于显示） declare -A distro_names distro_names[1]="Debian 12" distro_names[2]="Debian 11" distro_names[3]="CentOS 9 Stream" distro_names[4]="CentOS 8 Stream" distro_names[5]="Ubuntu 22.04" distro_names[6]="Ubuntu 24.04" distro_names[7]="AlmaLinux 8" distro_names[8]="AlmaLinux 9" distro_names[9]="Rocky Linux 8" distro_names[10]="Rocky Linux 9" for distro_option in $(seq 1 $distro_count); do echo "=====================================" echo "正在为 ${distro_names[$distro_option]} 创建模板，VMID: $current_vmid" echo "=====================================" # 创建模板 create_template $distro_option $current_vmid $vmbr $storage # VMID 递增 current_vmid=$((current_vmid + 1)) done } # 主函数 main() { echo "=====================================" echo "开始一键安装所有 Proxmox VE 模板" echo "VMID 将从 8000 开始递增" echo "=====================================" # 提示用户输入网络接口和存储 prompt_for_network_and_storage # 创建所有模板 create_all_templates echo "=====================================" echo "所有模板创建完成！" echo "创建的模板 VMID 范围：8000 - $((8000 + 10 - 1))" echo "=====================================" } # 运行主函数 main
平台操作系统：debian11 其他方法系统，方法类似先更新软件源并安装必要依赖sudo apt-get update sudo apt-get install -y figlet ruby rubygems sudo gem install lolcat sudo apt-get install -y cron代码内容sudo tee /usr/local/bin/update_xuanyuan_motd <<'EOF' #!/bin/bash { echo -e "\033[1;36m" figlet -f slant "CLOUD" | /usr/local/bin/lolcat echo -e "\033[0m" echo "==============================================" printf "%-12s %s\n" "主机IP:" "$(hostname -I | cut -d' ' -f1)" printf "%-12s %s\n" "系统版本:" "$(lsb_release -sd)" printf "%-12s %s\n" "运行时间:" "$(uptime -p | sed 's/up //')" printf "%-12s %s\n" "当前负载:" "$(cat /proc/loadavg | cut -d' ' -f1-3)" echo "==============================================" date +"生成时间: %Y-%m-%d %H:%M:%S" } > /etc/motd EOF设置权限并测试运行sudo chmod +x /usr/local/bin/update_xuanyuan_motd sudo /usr/local/bin/update_xuanyuan_motd创建每小时更新的cron任务sudo tee /etc/cron.d/update_motd <<EOF 0 * * * * root /usr/local/bin/update_xuanyuan_motd EOF重启cron服务sudo systemctl restart cron最终效果验证命令：查看当前MOTDcat /etc/motd查看定时任务状态systemctl status cron查看最近一次执行日志grep update_xuanyuan /var/log/syslog
前言我的PVE版本是8.3.0第一步：备份原文件进入修改文件的目录cd /usr/share/javascript/proxmox-widget-toolkit备份原文件，一定要记得备份哈！要不就惨了cp proxmoxlib.js proxmoxlib.js.bak第二步，修改proxmoxlib.js文件可以用nano、vim、vi，总之随便一种文本编辑器就行vi proxmoxlib.js第三步，查找包含orig_cmd的这句话找到如下现实的这行checked_command: function(orig_cmd) {第四步，在后面加上orig_cmd();和return;即可，如下checked_command: function(orig_cmd) { orig_cmd(); #<-----这里是第一个加的地方 return; #<-----这里是第二个加的地方，后面的不要动 Proxmox.Utils.API2Request( { url: '/nodes/localhost/subscription', method: 'GET', failure: function(response, opts) {最后，重启PVE代理服务systemctl restart pveproxy.service
在 Debian 12 上安装 DockerDocker 是一个开源的应用容器引擎，它使得开发者可以打包应用及其依赖到一个轻量级、可移植的容器中，并可以在任何地方运行。在这篇文章中，我将指导大家如何在 Debian 12 系统上安装 Docker。前提条件操作系统：本教程适用于 Debian 12（Bookworm）及以上版本。管理员权限：需要具有 sudo 权限来执行一些安装命令。步骤一：更新系统软件包首先，确保你的 Debian 12 系统是最新的。在安装 Docker 之前，建议更新所有的系统包，以确保软件包的安全性和稳定性。sudo apt update sudo apt upgrade -y步骤二：安装 Docker 安装的依赖包Docker 需要一些基础的依赖包，运行以下命令来安装这些包：sudo apt install apt-transport-https ca-certificates curl software-properties-common -y步骤三：添加 Docker 官方 GPG 密钥接下来，添加 Docker 官方的 GPG 密钥，以便我们可以安全地安装 Docker 的软件包。curl -fsSL https://download.docker.com/linux/debian/gpg | sudo gpg --dearmor -o /usr/share/keyrings/docker-archive-keyring.gpg步骤四：添加 Docker 官方仓库添加 Docker 的官方 APT 仓库到系统的软件源列表中：echo "deb [arch=amd64 signed-by=/usr/share/keyrings/docker-archive-keyring.gpg] https://download.docker.com/linux/debian $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null步骤五：更新软件包索引添加 Docker 仓库后，刷新本地的软件包索引：sudo apt update步骤六：安装 Docker现在，可以安装 Docker 引擎了。运行以下命令来安装 Docker 相关的包：sudo apt install docker-ce docker-ce-cli containerd.io -y步骤七：启动 Docker 服务安装完成后，我们需要启动 Docker 服务，并将其设置为开机自启。运行以下命令：sudo systemctl start docker sudo systemctl enable docker步骤八：验证 Docker 是否成功安装你可以通过运行以下命令来验证 Docker 是否安装成功：sudo docker --version sudo docker run hello-world如果 Docker 安装成功，你会看到类似以下的输出：Docker version 20.10.24, build 1f3f9c5 Hello from Docker! This message shows that your installation appears to be working correctly.步骤九：（可选）配置 Docker 无需 sudo 权限如果你希望在执行 Docker 命令时无需每次加 sudo，你可以将当前用户添加到 Docker 组：sudo usermod -aG docker $USER执行上述命令后，你需要退出当前会话并重新登录，或者使用以下命令立即生效：newgrp docker总结至此，Docker 已经成功安装在你的 Debian 12 系统上，并且可以开始使用它来创建和管理容器了。如果在使用过程中遇到任何问题，可以通过以下命令查看 Docker 服务的状态：sudo systemctl status docker希望本教程对你有所帮助！如果你在安装过程中遇到任何问题，欢迎在评论区留言，我会尽力解答。
如何使用 systemd 实现开机启动在 Linux 系统中，systemd 是一个强大的初始化系统和服务管理器，广泛用于启动和管理系统服务。通过 systemd，我们可以非常方便地配置脚本和程序在系统启动时自动运行。本文将介绍如何使用 systemd 来实现开机启动。1. 创建 systemd 服务文件要使自定义命令或脚本在系统启动时自动执行，首先需要创建一个 systemd 服务单元文件。我们以执行以下命令为例：nohup ./iptables-server -a :1086 -u admin -p xyidc123 > /dev/null 2>&1 &假设该命令的文件路径为 /root/iptables-web/iptables-server。步骤 1：创建服务文件首先，创建一个新的 systemd 服务文件。例如，我们将服务命名为 iptables-server.service。sudo nano /etc/systemd/system/iptables-server.service步骤 2：编辑服务文件在打开的文件中，添加以下内容：[Unit] Description=Start iptables server After=network.target [Service] ExecStart=/root/iptables-web/iptables-server -a :1086 -u admin -p xyidc123 WorkingDirectory=/root/iptables-web User=root Restart=always [Install] WantedBy=multi-user.targetDescription：服务的描述，可以自定义。After=network.target：确保该服务在网络服务启动后执行。ExecStart：指定要执行的命令及其参数。WorkingDirectory：设置命令执行的工作目录。User=root：指定以 root 用户身份运行该命令。Restart=always：确保服务在意外停止后会重新启动。WantedBy=multi-user.target：表示该服务将会在系统启动时自动启动。步骤 3：保存并退出编辑完成后，按 Ctrl+O 保存文件，按 Ctrl+X 退出编辑器。2. 重新加载 systemd 配置服务文件创建完成后，我们需要告诉 systemd 重新加载服务配置。sudo systemctl daemon-reload这条命令会重新加载所有服务文件，包括刚才我们创建的 iptables-server.service 文件。3. 启动服务接下来，我们可以手动启动服务来确认它是否能够正常运行。sudo systemctl start iptables-server.service您可以使用以下命令来检查服务是否正在运行：sudo systemctl status iptables-server.service如果服务启动正常，您应该能看到类似如下的输出：● iptables-server.service - Start iptables server Loaded: loaded (/etc/systemd/system/iptables-server.service; disabled; vendor preset: enabled) Active: active (running) since Sat 2024-12-09 10:24:10 UTC; 1min ago ...4. 设置开机自启如果服务可以正常启动，并且您希望它在每次系统启动时自动运行，可以通过以下命令启用该服务：sudo systemctl enable iptables-server.service该命令会创建必要的符号链接，使服务在系统启动时自动启动。步骤 5：重启系统测试为确保设置生效，您可以重启计算机并确认服务是否会在启动时自动运行。sudo reboot重启后，您可以使用以下命令检查服务状态：sudo systemctl status iptables-server.service如果服务在启动时成功运行，您会看到服务的状态是 active (running)。5. 总结通过使用 systemd，我们可以非常方便地将脚本和命令设置为开机自动启动。只需创建一个自定义的服务单元文件，配置启动命令，重新加载 systemd，并启用服务，就能确保它在每次系统启动时都自动执行。使用 systemd 配置开机启动不仅可以节省手动执行命令的时间，还能提高系统的自动化管理能力。
Root 用户无法通过 SSH 登录的问题及解决方案在 Linux 系统中，root 用户通常拥有最高的权限，允许进行系统级别的配置和操作。然而，出于安全考虑，很多 Linux 系统默认会禁用 root 用户通过 SSH 登录。如果您在使用 root 用户登录 SSH 时遇到问题，本篇博文将帮助您解决这一问题，并详细介绍如何配置防火墙（尤其是使用 IPT 防火墙时）确保 SSH 服务顺利运行。1. 检查 SSH 服务配置默认情况下，Linux 系统可能会禁止 root 用户通过 SSH 登录。这是出于安全性考虑，因为直接以 root 身份登录会增加暴力破解的风险。1.1 检查 sshd_config 配置文件要允许 root 用户通过 SSH 登录，首先需要编辑 SSH 配置文件 /etc/ssh/sshd_config。sudo nano /etc/ssh/sshd_config找到以下配置项：#PermitRootLogin prohibit-password将其修改为：PermitRootLogin yes或者，如果您希望仅允许通过密钥认证登录，可以设置为：PermitRootLogin without-passwordyes：允许使用密码或密钥认证登录。without-password：仅允许密钥认证，禁止密码认证。prohibit-password：禁止通过密码认证登录，仅允许密钥认证。修改完成后，保存文件并退出编辑器（按 Ctrl+O 保存，Ctrl+X 退出）。1.2 重启 SSH 服务配置更改后，您需要重启 SSH 服务才能使更改生效：sudo systemctl restart ssh2. 检查 IPT 防火墙配置如果您的系统使用的是 IPT（iptables）防火墙，确保防火墙规则允许 SSH 服务通过。默认情况下，iptables 可能会阻止外部访问 SSH 服务，特别是在新配置的服务器上。2.1 查看当前防火墙规则首先，检查当前防火墙规则，以确认是否已允许端口 22（SSH 默认端口）通过：sudo iptables -L您应该能看到类似以下的输出，其中包括允许 22 端口的规则：ACCEPT tcp -- anywhere anywhere tcp dpt:ssh如果没有显示允许端口 22 的规则，您需要手动添加规则。2.2 添加允许 SSH 通过的规则如果没有找到允许 SSH 的规则，可以使用以下命令添加规则：sudo iptables -A INPUT -p tcp --dport 22 -j ACCEPT这条命令会将一条规则添加到 INPUT 链中，允许所有来自外部的 TCP 流量访问端口 22（SSH）。2.3 保存防火墙配置如果您希望防火墙在系统重启后依然保持这些规则，需要保存当前的防火墙规则。使用以下命令保存：Debian/Ubuntu 系列系统：sudo iptables-save > /etc/iptables/rules.v4CentOS/RHEL 系列系统：sudo service iptables save2.4 检查防火墙状态使用以下命令确认防火墙规则已经生效：sudo iptables -L确保您能看到类似以下的规则：ACCEPT tcp -- anywhere anywhere tcp dpt:ssh3. 其他可能的原因3.1 检查 SSH 服务端口如果您修改了 SSH 服务的默认端口（22），确保防火墙允许新的端口通过。例如，假设您的 SSH 配置文件 /etc/ssh/sshd_config 中将端口修改为 2222：Port 2222在这种情况下，您需要允许端口 2222 通过防火墙：sudo iptables -A INPUT -p tcp --dport 2222 -j ACCEPT3.2 检查 SELinux 状态在某些系统（如 CentOS/RHEL）中，SELinux 可能会限制 SSH 访问。您可以通过以下命令检查 SELinux 的状态：sestatus如果 SELinux 启用了并限制了 SSH 访问，可以暂时禁用 SELinux 或调整相关规则以允许 SSH 登录。4. 测试 SSH 登录配置完成后，您可以尝试通过 SSH 登录到服务器。使用以下命令：ssh root@your_server_ip如果一切配置正确，您将能够成功登录到系统。如果仍然无法登录，请再次检查 SSH 配置文件和防火墙设置。5. 总结如果您遇到 root 用户无法通过 SSH 登录的问题，通常是由于 SSH 服务的配置问题或防火墙的访问控制导致的。通过调整 /etc/ssh/sshd_config 文件、配置 IPT 防火墙规则，您可以解决这个问题并确保 root 用户能够顺利通过 SSH 登录。为了保证系统安全，建议：使用密钥认证而非密码认证；禁用不必要的 root 登录；配置防火墙并定期审查系统设置。
前言因为自己买了小主机，自己折腾，记录下，以免后期需要用的时候，不用翻找！如何启用 SSH 服务并远程连接 Linux 系统在 Linux 系统中，SSH（Secure Shell）是远程管理和配置服务器的常用工具。通过 SSH，您可以安全地连接到远程主机，执行命令，进行文件传输等操作。本文将指导您如何在 Linux 系统上启用和配置 SSH 服务。1. 安装 SSH 服务默认情况下，一些 Linux 发行版可能没有安装 SSH 服务。首先，确保您的系统已经安装了 SSH 服务。Debian/Ubuntu 系列系统：sudo apt update sudo apt install openssh-serverCentOS/RHEL 系列系统：sudo yum install openssh-server安装完成后，您可以通过运行以下命令验证是否安装成功：ssh -V如果成功，您将看到 OpenSSH 版本号。2. 启动和启用 SSH 服务安装完 SSH 服务后，接下来需要启动 SSH 服务，并设置它开机自启。启动 SSH 服务：sudo systemctl start ssh设置 SSH 服务开机自启：sudo systemctl enable ssh检查 SSH 服务状态：sudo systemctl status ssh如果 SSH 服务已启动，您会看到类似以下的输出：● ssh.service - OpenBSD Secure Shell server Loaded: loaded (/lib/systemd/system/ssh.service; enabled; vendor preset: enabled) Active: active (running) since Sat 2024-12-09 10:24:10 UTC; 1h 15min ago ...3. 配置 SSH 服务SSH 服务的配置文件通常位于 /etc/ssh/sshd_config。您可以编辑这个文件来调整 SSH 的设置，诸如允许/禁止 root 登录、修改默认端口等。编辑 SSH 配置文件：sudo nano /etc/ssh/sshd_config常见的配置项：允许 root 用户登录：PermitRootLogin yes修改为 yes 以允许 root 用户通过 SSH 登录，prohibit-password 表示仅允许密钥认证，no 则禁止 root 登录。更改 SSH 默认端口：Port 22如果您想更改 SSH 默认端口（提高安全性），可以修改为其他端口，例如 Port 2222。启用密码认证：PasswordAuthentication yes确保设置为 yes，否则将只能使用密钥认证登录。编辑完成后，按 Ctrl+O 保存文件，再按 Ctrl+X 退出 nano 编辑器。重启 SSH 服务以应用更改：sudo systemctl restart ssh4. 配置防火墙确保防火墙允许 SSH 服务通过。以下是一些常见防火墙配置命令：Debian/Ubuntu 系列系统（使用 ufw 防火墙）：sudo ufw allow sshCentOS/RHEL 系列系统（使用 firewalld）：sudo firewall-cmd --permanent --add-service=ssh sudo firewall-cmd --reload检查防火墙状态：sudo ufw status或者：sudo firewall-cmd --list-all5. 测试 SSH 连接配置完成后，您可以从远程机器使用 SSH 客户端连接到您的 Linux 系统。假设您的 Linux 系统 IP 地址为 192.168.1.100，可以在远程机器上执行以下命令：ssh username@192.168.1.100如果使用的是 root 用户，命令为：ssh root@192.168.1.100系统将提示您输入密码，输入正确的密码后，您将成功连接到远程 Linux 系统。6. 其他常用 SSH 操作生成 SSH 密钥对（推荐用于无密码登录）：ssh-keygen -t rsa -b 4096将公钥复制到远程主机：ssh-copy-id username@192.168.1.100通过 SSH 远程执行命令：ssh username@192.168.1.100 'ls -l'总结通过上述步骤，您已成功在 Linux 系统上启用了 SSH 服务，并能够通过远程连接管理您的服务器。SSH 是一种非常强大且安全的远程连接工具，广泛应用于系统管理和维护中。为了提高安全性，建议使用密钥认证代替密码认证，并定期审查 SSH 配置。