qemu linux内核(5.10.209)开发环境搭建
ahcoder 2025-05-03 11:45 14 浏览
版本信息
宿主机:ubuntu 20.04.6 LTS (Focal Fossa)
虚拟机:ubuntu 20.04.6 LTS (Focal Fossa)
安装宿主机的步骤省略,和一般的在vmware中安装虚拟机没有任何区别。
需要注意的是需要打开Intel VT-x
如果启动虚拟机报告此平台不支持虚拟化的Intel VT-x/EPT. 不使用虚拟化的Intel VT-x/EPT,是否继续,参考下面的文章解决.
https://blog.csdn.net/2301_77695535/article/details/146309899
宿主机安装QEMU/KVM和Virsh
Virsh是Virtual Shell的缩写,是一个用于管理虚拟机的命令行工具。你可以使用Virsh创建、编辑、启动、停止、关闭和删除VM。Virsh目前支持KVM,LXC,Xen,QEMU,OpenVZ,VirtualBox和VMware ESX。这里我们使用Virsh管理QEMU/KVM虚拟机。
在安装之前,首先要确认你的CPU是否支持虚拟化技术。使用grep查看cpuinfo是否有"vmx"(Intel-VT 技术)或"svm"(AMD-V 支持)输出:
egrep "(svm|vmx)" /proc/cpuinfo
某些CPU型号在默认情况下,BIOS中可能禁用了VT支持。我们需要再检查BIOS设置是否启用了VT的支持。使用kvm-ok命令进行检查:
sudo apt install cpu-checker
kvm-ok
如果输出为:
INFO: /dev/kvm exists
KVM acceleration can be used
证明CPU的虚拟化支持已经在BIOS中启用。
运行下面的命令安装QEMU/KVM和Virsh:
sudo apt install qemu-kvm libvirt-daemon-system libvirt-clients bridge-utils virtinst virt-manager
检查libvirt守护程序是否已经启动:
sudo systemctl is-active libvirtd
active
如果没有输出active,运行下面的命令启动libvertd服务:
sudo systemctl enable libvirtd
sudo systemctl start libvirtd
在宿主机中安装qemu虚拟机
创建一个虚拟机镜像,大小为40G,qow2格式动态分配磁盘占用空间。
qemu-img create -f qcow2 ubuntutest.img 40G
创建虚拟机系统,安装操作系统:
qemu-system-x86_64 \
-name ubuntutest \
-smp 2 \
-m 4096 \
-hda ubuntutest.img \
-cdrom ubuntu-20.04.6-live-server-amd64.iso \
-boot d
按照步骤,配置安装即可,这一步和正常的虚拟机安装没有什么区别。
注意这里我没有添加-enable-kvm,这可能会影响gdb的软件断点。
配置上网
方案1:自建tap网卡NAT上网
宿主机创建TAP设备
sudo ip tuntap add dev tap0 mode tap
sudo ip addr add 192.168.100.1/24 dev tap0
sudo ip link set tap0 up
宿主机配置IP转发及NAT规则
sudo sysctl -w net.ipv4.ip_forward=1
sudo iptables -t nat -A POSTROUTING -s 192.168.100.0/24 -o ens33 -j MASQUERADE
sudo iptables -A FORWARD -i tap0 -j ACCEPT
启动带TAP的QEMU
qemu-system-x86_64 \
-enable-kvm \
-m 4096 \
-drive file=./ubuntutest.img \
-boot d \
-net nic -net tap,ifname=tap0,script=no,downscript=no
配置虚拟机的网络为192.168.100.0/24网段中的任意一个地址(例如192.168.100.10)
打开netplan的配置文件,修改地址后,使用sudo netplan apply重启网络。
# This is the network config written by 'subiquity'
network:
ethernets:
ens3:
dhcp4: no
addresses:
- 192.168.100.10/24
routes:
- to: default
via: 192.168.100.1
nameservers:
addresses: [8.8.8.8]
version: 2
利用virbr0实现nat上网
创建并配置bridge.conf
- 文件路径:通常位于/etc/qemu/或/usr/local/etc/qemu/(取决于安装方式)。使用以下命令创建:
sudo mkdir -p /etc/qemu
sudo vim /etc/qemu/bridge.conf
内容示例:
allow virbr0 # 若使用libvirt默认桥接接口
接下来启动时指定使用virbr0 bridge上网。
qemu-system-x86_64 \
-enable-kvm \
-m 4096 \
-drive file=./ubuntutest.img -boot d \
-netdev bridge,id=net0,br=virbr0 \
-device virtio-net-pci,netdev=net0
配置虚拟机网络时,配置和virbr0一个网段的,即192.168.122.0/24(例如192.168.122.10)
下载linux内核并且编译
安装编译依赖
首先我们需要安装编译内核用到的依赖包,我是在宿主机上编译linux内核代码的,因此下面的语句直接在宿主机上执行。
sudo apt install libncurses5-dev libssl-dev bison flex libelf-dev gcc make openssl libc6-dev dwarves
下载linux内核代码并构建
下载Linux内核代码,这里我使用的是5.10.209版本
https://www.kernel.org/pub/linux/kernel/v5.x/linux-5.10.209.tar.gz
使用下面的语句make kernel编译参数:
sudo make menuconfig
为了构建能够调试的内核,我们需要配置以下几个参数。
- CONFIG_DEBUG_INFO 在内核和内核模块中包含调试信息,这个选项在幕后为gcc使用的编译器参数增加了-g选项。
这个选项的菜单路径为:
Kernel hacking --->
Compile-time checks and compiler options --->
[*] Compile the kernel with debug info
也可以直接在.config中设置CONFIG_DEBUG_INFO。
CONFIG_DEBUG_INFO=y
- CONFIG_FRAME_POINTER 这个选项会将调用帧信息保存在寄存器或堆栈上的不同位置,使gdb在调试内核时可以更准确地构造堆栈回溯跟踪(stack back traces)。
也可以在.config中设置:
CONFIG_FRAME_POINTER=y
- 启用CONFIG_GDB_SCRIPTS,但要关闭CONFIG_DEBUG_INFO_REDUCED。
CONFIG_GDB_SCRIPTS=y
CONFIG_DEBUG_INFO_REDUCED=n
- CONFIG_KGDB 启用内置的内核调试器,该调试器允许进行远程调试。
Kernel hacking --->
Generic Kernel Debugging Instruments --->
[*] KGDB: kernel debugger
CONFIG_KGDB=y
- 关闭CONFIG_RANDOMIZE_BASE设置
CONFIG_RANDOMIZE_BASE的位置在如下位置可以找到:
Processor type and features --->
Randomize the address of the kernel image (KASLR)
或者直接在.config中添加下面的语句
CONFIG_RANDOMIZE_BASE=n
KASLR会更改引导时放置内核代码的基地址。如果你在内核配置中启用了KASLR(CONFIG_RANDOMIZE_BASE=y),则无法从gdb设置断点。设置完必要的内核参数后,我们开始编译内核:
sudo make -j8
sudo make INSTALL_MOD_STRIP=1 modules_install
sudo make install
make modules_install会将module文件安装到/lib/modules/5.10.209,并且最好添加上INSTALL_MOD_STRIP=1,否则initrd.img体积会很大。
编译大概需要30G空间,因此需要事先准备好>=30G的磁盘。
这些步骤执行完毕之后,我们就得到了需要的linux内核镜像bzImage(vmlinuz)和initrd.img
xu@xu-dev:~/work/linux-5.10.209$ ls /boot/ -alh |grep 5.10.209
-rw-r--r-- 1 root root 243K 4月 20 19:34 config-5.10.209
lrwxrwxrwx 1 root root 19 4月 20 19:34 initrd.img -> initrd.img-5.10.209
-rw-r--r-- 1 root root 60M 4月 20 19:34 initrd.img-5.10.209
-rw-r--r-- 1 root root 5.5M 4月 20 19:34 System.map-5.10.209
lrwxrwxrwx 1 root root 16 4月 20 19:34 vmlinuz -> vmlinuz-5.10.209
-rw-r--r-- 1 root root 14M 4月 20 19:34 vmlinuz-5.10.209
编译的产物介绍
在Linux内核编译过程中,生成的文件根据功能可分为以下几类,以下是详细介绍及对应的文件作用与来源:
核心可执行文件
- vmlinux 描述:原始的、未经压缩的内核可执行文件,包含完整的符号表和调试信息,体积较大。 生成路径:位于内核源码根目录或 arch/<架构>/boot/compressed/ 目录下。 用途:用于调试和分析内核崩溃问题,不直接用于启动系统。 来源:编译过程通过链接 head-y、init-y、core-y 等目标文件生成 。
- zImage** 与 **bzImage 描述:压缩后的内核镜像文件,bzImage(Big zImage)支持更大体积的内核(超过512KB时使用)。 生成路径:位于 arch/<架构>/boot/ 目录下(如 arch/x86/boot/bzImage)。 结构:由 setup.bin(引导程序)和压缩后的 vmlinux 拼接而成,附加解压头信息。 用途:直接用于系统引导,是大多数Linux发行版的默认内核文件 。
- uImage 描述:专为U-Boot引导程序设计的镜像文件,在 zImage 基础上添加U-Boot头部信息。 生成路径:需通过 mkimage 工具处理 zImage 生成。 用途:嵌入式系统中配合U-Boot使用 。
引导相关文件
- System.map 描述:内核符号映射文件,记录所有函数和变量的内存地址。 生成路径:内核源码根目录下。 用途:调试时关联地址与符号,例如分析内核崩溃日志 。
- initrd.img** 或 **initramfs 描述:初始内存文件系统,包含启动早期所需的临时驱动和工具(如磁盘驱动、文件系统模块)。 生成路径:通过 mkinitramfs 或 dracut 生成,存放于 /boot/ 目录。 用途:解决根文件系统挂载前的依赖问题 。
内核模块文件
- .ko** 文件(Kernel Object)** 描述:动态可加载内核模块,按需插入内核运行。 生成路径:各驱动或功能模块目录下(如 drivers/net/ethernet/)。 安装路径:通过 make modules_install 安装到 /lib/modules/<内核版本>/ 目录。 用途:灵活扩展内核功能(如添加新硬件驱动) 。
配置文件与日志
- .config 描述:内核编译的配置文件,记录所有选中的功能选项(如 CONFIG_DEBUG_INFO=y)。 生成路径:内核源码根目录下。 来源:通过 make menuconfig 或复制默认配置(如 arch/arm/configs/s5pv210_defconfig)生成 。
- vmlinux.lds 描述:链接脚本文件,定义内核各段(代码、数据、堆栈)的内存布局。 生成路径:arch/<架构>/kernel/ 目录下。 用途:指导链接器生成 vmlinux 。
中间文件与工具生成文件
- .o** 与 **built-in.o 描述:编译过程中生成的中间目标文件,built-in.o 是同一目录下所有 .o 文件的合并。 生成路径:各子模块目录下(如 init/built-in.o)。 用途:逐步构建最终内核镜像 。
- 设备树文件(.dtb) 描述:描述硬件拓扑结构的二进制文件,用于嵌入式系统(如ARM架构)。 生成路径:通过设备树编译器(DTC)从 .dts 文件生成,位于 arch/<架构>/boot/dts/。 用途:适配不同硬件平台 。
启动管理与版本标识
- vmlinuz-<版本号> 描述:安装到 /boot/ 目录的压缩内核镜像,通常为 bzImage 的符号链接。 用途:Grub等引导程序通过该文件加载内核 。
- config-<版本号> 描述:.config 文件的备份,保存编译时的完整配置。 生成路径:/boot/ 目录下 。
总结对比表
文件类型 | 关键文件 | 作用 | 生成命令 |
核心镜像 | vmlinux, bzImage | 内核执行与引导 | make, make bzImage |
模块 | .ko | 动态扩展内核功能 | make modules |
配置 | .config | 记录编译选项 | make menuconfig |
引导支持 | initrd.img | 早期启动依赖加载 | mkinitramfs |
符号映射 | System.map | 调试符号地址映射 | 自动生成 |
设备树 | .dtb | 嵌入式硬件描述 | make dtbs |
内核debug
在获取内核镜像bzImage和initrd.img之后,就可以使用其启动qemu虚拟机。
注意我这里的调试是使用qemu的-kernel和-initrd去直接加载内核,而没有使用grub去加载内核。
我的qemu的启动脚本如下所示:
qemu-system-x86_64 \
-smp 2 \
-m 4096 \
-S -s \
-drive file=/home/xu/work/ubuntutest.img \
-netdev bridge,id=net0,br=virbr0 \
-device virtio-net-pci,netdev=net0 \
-kernel /home/xu/work/kernel-with-rwx/bzImage \
-initrd /home/xu/work/kernel-with-rwx/initrd.img-5.10.209 \
-append "root=/dev/mapper/ubuntu--vg-ubuntu--lv ro maybe-ubiquity console=ttyS0\
-nographic
- -smp 2 分配2个虚拟CPU核心(vCPU),默认情况下每个核心为单线程、单插槽。若需更细粒度控制(如多插槽、多线程),可扩展为-smp 2,sockets=1,cores=2,threads=1
- -m 4096 为虚拟机分配4096MB(4GB)内存。QEMU默认分配128MB,此参数需根据宿主机资源和虚拟机需求调整
- -S 启动时暂停CPU执行,等待外部调试器(如GDB)连接后继续运行,常用于内核调试
- -s 启用GDB调试服务器,默认监听本地端口1234。结合-S可实现从启动阶段调试内核
- -drive file=/home/xu/work/ubuntutest.img 加载名为ubuntutest.img的磁盘镜像作为主硬盘。默认接口类型为if=virtio(高性能虚拟化驱动),若未指定格式,QEMU自动检测(如qcow2或raw)
- -netdev bridge,id=net0,br=virbr0 创建桥接网络后端,连接到宿主机的virbr0网桥,允许虚拟机通过宿主机网络接口访问外部 。
- -device virtio-net-pci,netdev=net0 为虚拟机添加虚拟网卡,使用virtio-net-pci驱动(高性能半虚拟化网卡),绑定到上述网络后端。
- -kernel /home/xu/work/kernel-with-rwx/bzImage 指定Linux内核镜像文件bzImage,绕过虚拟机的BIOS引导,直接加载内核
- -initrd /home/xu/work/kernel-with-rwx/initrd.img-5.10.209 使用initrd.img-5.10.209作为初始内存文件系统,包含启动初期所需的模块和工具
- -append "root=/dev/mapper/ubuntu--vg-ubuntu--lv ro maybe-ubiquity console=ttyS0"``root=/dev/mapper/ubuntu--vg-ubuntu--lv:指定根文件系统位置(LVM逻辑卷)。ro:以只读模式挂载根文件系统,通常需后续切换为读写模式。console=ttyS0:将控制台输出重定向到串口ttyS0,配合-nographic使用。(ubuntu系统通过df -h查看根文件系统的路径)。
上面提到,还有一种是使用grub启动内核,相对要麻烦一点,需要把宿主机上的内核拷贝到虚拟机上,并执行make modules_install和make install,然后启动时使用-boot d从硬盘加载内核。
qemu-system-x86_64 \
-enable-kvm \
-smp 2 \
-m 4096 \
-drive file=./ubuntutest.img -boot d \
-netdev bridge,id=net0,br=virbr0 \
-device virtio-net-pci,netdev=net0
不过我觉得使用-kernel和-initrd更为方便,也更加推荐。
接下来启动gdb调试,使用另一个终端打开gdb:
xu@xu-dev:~/work/linux-5.10.209$ gdb vmlinux -q
Reading symbols from vmlinux...
warning: File "/home/xu/work/linux-5.10.209/scripts/gdb/vmlinux-gdb.py" auto-loading has been declined by your `auto-load safe-path' set to "$debugdir:$datadir/auto-load".
To enable execution of this file add
add-auto-load-safe-path /home/xu/work/linux-5.10.209/scripts/gdb/vmlinux-gdb.py
line to your configuration file "/home/xu/.gdbinit".
To completely disable this security protection add
set auto-load safe-path /
line to your configuration file "/home/xu/.gdbinit".
For more information about this security protection see the
"Auto-loading safe path" section in the GDB manual. E.g., run from the shell:
info "(gdb)Auto-loading safe path"
使用gdb远程连接:
(gdb) target remote :1234
Remote debugging using :1234
0x000000000000fff0 in exception_stacks ()
下断点
(gdb) b start_kernel
Breakpoint 1 at 0xffffffff82daad61: file init/main.c, line 847.
继续执行,触发断点:
(gdb) c
Continuing.
Thread 1 hit Breakpoint 1, start_kernel () at init/main.c:847
单步调试:
847 {
(gdb) n
851 set_task_stack_end_magic(&init_task);
(gdb) n
852 smp_setup_processor_id();
(gdb) n
855 cgroup_init_early();
(gdb)
问题
证书找不到
CC [M] kernel/kheaders.o
CC certs/system_keyring.o
make[1]: *** No rule to make target 'debian/canonical-certs.pem', needed by 'certs/x509_certificate_list'. Stop.
make: *** [Makefile:1832: certs] Error 2
解决办法:
1.修改
CONFIG_SYSTEM_TRUSTED_KEYS
修改前:原变量有值
CONFIG_SYSTEM_TRUSTED_KEYS="
debian/canonical-certs.pem"
修改后:将该变量赋空值
CONFIG_SYSTEM_TRUSTED_KEYS=""
2.修改
CONFIG_SYSTEM_REVOCATION_KEYS(可选)
如果
CONFIG_SYSTEM_REVOCATION_KEYS的值不为空的话,也将其赋空值。
修改前:原变量有值
CONFIG_SYSTEM_REVOCATION_KEYS="
debian/canonical-revoked-certs.pem"
修改后:将该变量赋空值
CONFIG_SYSTEM_REVOCATION_KEYS=""
内核停留在“loading initial ramdisk”很长时间并且启动之后kernel crash报告引导内核时报错Kernel panic not syncing : System is deadlocked on memory
编译内核的过程中,当安装内核模块未使用INSTALL_MOD_STRIP=1时,会导致initrd文件过大,导致启动时卡在解压initrd上花费过度的时间。
例如这里,我的initrd.img是1.2G。
为了解决该问题,需要在安装module的时候添加INSTALL_MOD_STRIP=1
sudo make INSTALL_MOD_STRIP=1 modules_install
sudo make install
kernel crash报告引导内核时报错Kernel panic not syncing : System is deadlocked on memory
这个问题和initrd.img相关。一种方式是通过减小initrd.img解决,还有一种方式就是通过调大虚拟机内存解决。
gdb软件中断无法触发,硬件中断可以触发
qemu如果启动时指定了-enable-kvm,会导致该问题。
如果启动的时候指定了-enable-kvm,则设置断点时需要使用硬件断点,例如
hb start_kernel
PS
如何清理内核编译产物
若在编译并安装 Linux 内核后希望卸载,以下是具体操作步骤及注意事项:
步骤 1:确认内核版本及安装路径
- 查看已安装的内核版本:
ls /boot | grep vmlinuz # 列出所有内核文件
uname -r # 查看当前正在运行的内核版本(避免误删)
- 确认手动编译安装的内核版本:
假设目标卸载的内核版本为 5.18.8,需确保其不在 uname -r 的输出中,否则删除后可能导致系统无法启动。
步骤 2:手动删除内核相关文件
手动编译安装的内核文件分散在多个目录中,需按路径逐一删除:
- 删除 /boot 目录下的内核文件:
sudo rm -rf /boot/vmlinuz-5.18.8
sudo rm -rf /boot/initrd.img-5.18.8
sudo rm -rf /boot/config-5.18.8
sudo rm -rf /boot/System.map-5.18.8
- 删除内核模块目录:
sudo rm -rf /lib/modules/5.18.8
- 删除内核源码目录(可选):
sudo rm -rf /usr/src/linux-5.18.8
- 清理 initramfs 残留:
sudo rm -rf /var/lib/initramfs-tools/5.18.8
步骤 3:更新 GRUB 引导配置
删除内核后需更新 GRUB,避免残留无效启动项:
sudo update-grub
步骤 4:重启系统
sudo reboot
重启后通过 uname -r 确认当前内核版本是否已切换至其他可用版本。
参考文章
https://github.com/mz1999/blog/blob/master/docs/gdb-kernel-debugging.md
相关推荐
- ClickHouse日志平台这样建,分分钟秒掉ELK
-
目前业界的日志生态,最常用的是ELK,其次就是ClickHouse,本文会演示如何使用Vector+ClickHouse来采集Nginx日志并做清洗,最终写入ClickHouse。至...
- nginx打印请求头日志方法-openresty
-
一、前言之前想用nginx打印收到的请求的请求头,但是只找到打印请求体的,没有打印请求头的,感觉原版nginx不支持。建议如果想打印请求头,先换成openresty(本人安装的是openresty-1...
- 文心快码帮你解大厂面试题:如何使用shell找到access log?
-
【大厂面试真题】系列,带你攻克大厂面试真题,秒变offer收割机!今日问题:在8g内存的机器,能否启动一个7G堆大小的java进程?一起看看文心快码BaiduComate给出的答案吧!如果这个问题你...
- Nginx奇技淫巧之:按日期自动生成日志文件
-
时光闹钟app开发者,请关注我,后续分享更精彩!坚持原创,共同进步!前言之前文章:Nginx奇技淫巧之:用户行为埋点数据采集实现,介绍了Nginx获取post请求body参数生成日志文件的方法。当业务...
- Nginx 日志文件详解:监控与诊断利器
-
随着互联网技术的快速发展,Nginx已成为最受欢迎的Web服务器之一,其稳定性、高性能和灵活性备受推崇。Nginx日志文件是Nginx服务器中非常重要的组成部分,对于监控和诊断Web应...
- Nginx从入门到放弃05-访问日志与日志切割
-
设置访问日志当我们访问nginx服务时,nginx会记录日志,nginx日志分两种,一种是访问日志,一种是错误日志,访问日志记录在”access.log”文件中,错误日志记录在”error.log”文...
- nginx系列:常用利用shell统计日志
-
0x01:根据访问IP统计UVUV(UniqueVisitor)独立访客,统计访问某站点的用户数;IP(InternetProtocol)独立IP数,是指独立的浏览了页面的不同IP,即统计不同的I...
- Linux 必须重点监控的 17 个日志文件:运维与安全必备指南
-
在Linux系统的日常运维与安全管理中,日志文件的重要性不言而喻。日志不仅记录着系统运行的点点滴滴,更是排查故障、发现异常、提前预警的第一手证据。作为一名系统管理员、安全工程师,甚至普通开发者,了...
- nginx 常用日志参数(nginx日志详解)
-
Nginx提供了多种日志参数(变量),可以用来记录请求的不同方面。常用日志参数$remote_addr:客户端的IP地址。$remote_user:客户端用户名。$time_local:局部时...
- GoAccess轻量nginx日志分析工具(nginx日志收集方案)
-
什么是GoAccessGoAccess是一款开源、实时,运行在命令行终端下的Web日志分析工具。该工具提供快速、多样的HTTP状态统计。分析结果,可以通过XShell等客户端工具查看,并...
- 后端实践:Nginx日志配置(超详细)(nginx日志配置文件)
-
作者:antwang来源:https://juejin.im/post/5aa09bb3f265da238f121b6c前言Nginx日志对于统计、系统服务排错很有用。Nginx日志主要分为两种:...
- Nginx access_log 运行日志查询和配置
-
1.介绍当我们学会Nginx的基本配置之后,可以通过Nginx配置Service代理。管理服务器所有的http和https请求。那么接下来就需要了解Nginx的日志控制,以及相关的文档查看了。你通过...
- Nginx记录用户请求Header到access log
-
为了统计和其它用途,经常有人需要自定义Nginx日志,把http请求中的某个字段记录到日志中,刚好在看lua+nginx的文章,第一想到的是用lua赋值来做,但是想想有点小恶心,于是Google了一番...
- 介绍五款Web服务器日志分析软件(web服务器日志是什么)
-
每个站长必须要看的数据统计表,都是由日志分析软件统计和分析网站情况所得出的。日志分析软件是一种解析Nginx/Apache/IIS/Lighttpd和任何其他Web服务器日志文件的软件...
- Nginx系列:Nginx自带后端健康检查
-
严格说Nginx并没有自带针对负载均衡后端节点的健康检查功能,但是可以通过默认自带的ngx_http_proxy_module模块和ngx_http_upstream_module模块中的相关指令...
- 一周热门
- 最近发表
- 标签列表
-
- linux 远程 (37)
- u盘 linux (32)
- linux 登录 (34)
- linux 路径 (33)
- linux 文件命令 (35)
- linux 是什么 (35)
- linux 界面 (34)
- 查看文件 linux (35)
- linux 语言 (33)
- linux代码 (32)
- linux 查看命令 (33)
- 关闭linux (34)
- root linux (33)
- 删除文件 linux (35)
- linux 主机 (34)
- linux与 (33)
- linux 函数 (35)
- linux .ssh (35)
- cpu linux (35)
- linux 防火墙 (33)
- linux 镜像 (34)
- linux ip地址 (34)
- linux 用户查看 (33)
- nginx配置 解析 (37)
- nginx 频率限制 (34)