博客

  • LinuxNFS实验和Samba实验

    NFS基础服务部署和远程挂载使用

    # 两台机器初始化均关闭防火墙和selinux
    systemctl stop firewalld      # 停止防火墙
    systemctl disable firewalld   # 禁用防火墙
    setenforce 0
    vim /etc/selinux/config # 改为disable
    SELINUX=disabled
    
    # 机器1
    192.168.18.129/24  # 部署nfs服务端
    
    # 命令合集
    dnf install nfs-utils  # 安装nfs服务相关组件  # 新的协议不用rpcbind管理,直接nfs服务
    mkdir /nfsdir      # 共享此目录(可以考虑如何加一块新盘共享)
    vim /etc/exports  # 写入下方内容
    /nfsdir 192.168.18.142(rw,sync,no_root_squash) # 共享的本地路径/nfsdir,允许访问的客户端IP地址,(读写权限|同步写入|客户端以 root 用户访问时,服务端保留其 root 身份,不对其进行降权)
    systemctl start rpcbind.service   # 启动rpc服务
    systemctl enable rpcbind.service  # 开机允许自启
    systemctl start nfs-server.service  # 启动nfs服务端
    systemctl enable nfs-server.service # 开机允许自启
    exportfs -v   # 查看本机所有nfs共享 -r 参数可用于reload
    
    # 机器2
    192.168.18.142/24  # 客户端,将nfs目录挂载为远程目录,可读写
    
    # 命令合集
    dnf install showmount
    showmount -e 192.168.18.129  # 查看目标nfs服务器有哪些可挂载点
    mkdir /mnt/nfs        # 创建挂载点
    mount 192.168.18.129:/nfsdir /mnt/nfs/   #挂载
    df -Th  # 查看挂载信息
    # 也可以永久挂载
    vim /etc/fstab
    192.168.18.129:/nfsdir                  /mnt/nfs/      nfs4     defaults        0 0 

    image-20260803191412925

    image-20260803205558182

    autofs自动挂载

    做此步骤前先将上一步骤挂载的文件系统卸载,且如果永久挂在,删除/etc/fstab中配置文件

    dnf install -y autofs
    vim /etc/auto.master
    /mnt/nfs        /etc/auto.nfs   # 增加此行,意味着后续auto.nfs中配置的挂载信息,将会自动挂载到/mnt/nfs下
    vim /etc/auto.nfs               #新建子配置文件
    servernfsdir -fstype=nfs4,rw,soft    192.168.18.129:/nfsdir  # 将nfs服务器的nfsdir以servernfsdir名称挂载,效果是,当访问/mnt/nfs/servernfsdir目录,会自动触发nfs挂载
    systemctl start autofs.service  # 启动自动挂载服务
    systemctl enable autofs.service
    
    # 测试
    df -Th # 此时没有nfs
    cd /mnt/nfs && ls  # 此时没有任何文件夹
    cd /mnt/nfs/servernfsdir # 此时触发自动挂载
    df -Th # 可以看到nfs挂载条目

    image-20260803213607796


    /etc/auto.master 的作用

    这是 autofs 的总控配置文件,定义了:

    1. 监控哪些目录
    2. 每个监控目录对应的子配置文件
    3. 全局超时时间

    ==原理==:

    ┌─────────────────────────────────────────────────────────────────────────────┐ │ 用户访问流程 │ └─────────────────────────────────────────────────────────────────────────────┘

                             用户执行
                                ↓
                    cd /mnt/nfs/servernfsdir
                                ↓
                    ┌───────────────────────┐
                    │  autofs 接管访问请求  │
                    └───────────────────────┘
                                ↓
                    ┌───────────────────────┐
                    │  读取 /etc/auto.master │
                    │  找到 /mnt/nfs 对应   │
                    │  /etc/auto.nfs        │
                    └───────────────────────┘
                                ↓
                    ┌───────────────────────┐
                    │  读取 /etc/auto.nfs   │
                    │  查找 "servernfsdir"  │
                    │  找到映射规则:       │
                    │  192.168.226.6:/nfsshare│
                    └───────────────────────┘
                                ↓
                    ┌───────────────────────┐
                    │  执行挂载命令          │
                    │  mount -t nfs4 -o     │
                    │  rw,soft              │
                    │  192.168.226.6:/nfsshare│
                    │  /mnt/nfs/servernfsdir│
                    └───────────────────────┘
                                ↓
                    ┌───────────────────────┐
                    │  挂载成功!            │
                    │  用户进入              │
                    │  /mnt/nfs/servernfsdir │
                    └───────────────────────┘
                                ↓
                    ┌───────────────────────┐
                    │  5分钟不访问          │
                    │  → 自动卸载           │
                    │  (释放资源)          │
                    └───────────────────────┘

    映射关系图 text ┌─────────────────────────────────────────────────────────────────────────────┐ │ 映射关系 │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ 用户访问入口 真实挂载目标 │ │ ┌─────────────────────┐ ┌─────────────────────────┐ │ │ │ /mnt/nfs/ │ │ 192.168.226.6:/nfsshare│ │ │ │ servernfsdir │ ═══════════► │ (NFS服务器共享目录) │ │ │ └─────────────────────┘ └─────────────────────────┘ │ │ │ │ │ │ │ │ │ │ ▼ ▼ │ │ ┌─────────────────────────────────────────────────────────────────┐ │ │ │ /etc/auto.nfs 映射规则 │ │ │ │ │ │ │ │ servernfsdir -fstype=nfs4,rw,soft 192.168.226.6:/nfsshare │ │ │ │ ↑ ↑ ↑ │ │ │ │ │ │ │ │ │ │ │ 触发点名称 挂载选项 真实服务器:共享目录 │ │ │ └─────────────────────────────────────────────────────────────────┘ │ │ │ └─────────────────────────────────────────────────────────────────────────────┘

    ┌─────────────────────────────────────────────────────────────────────────────┐ │ autofs = 监控系统 + 触发器 │ ├─────────────────────────────────────────────────────────────────────────────┤ │ │ │ 1. 监控功能:autofs 是一个守护进程,持续监控指定的目录访问 │ │ │ │ 2. 触发功能:一旦检测到用户尝试访问监控目录,autofs 立即响应 │ │ │ │ 3. 执行动作:根据配置文件执行对应的挂载操作 │ │ │ │ 4. 清理功能:监控闲置时间,超时自动卸载 │ │ │ └─────────────────────────────────────────────────────────────────────────────┘

    案例参考课件部分

    其他参考

    角色Web 世界网络文件系统世界
    具体软件 / 业务应用浏览器 & Web 服务器 (如 Chrome / Nginx)负责处理网页如何展示、网站业务逻辑NFS 客户端 & NFS 服务端 (内核模块)负责处理文件打开、读写、权限等文件逻辑
    底层应用层通信协议HTTP 协议规定了请求怎么发(GET/POST)、数据怎么打包(JSON/HTML)ONC RPC 协议规定了远程函数怎么调用(Call/Reply)、数据怎么打包(XDR)

    NFSv2/3

    [ 客户端 (Client) ]                                       [ 服务端 (Server) ]
            |                                                         |
            |======= 第一轮:控制面服务寻址 (Portmapper) ======================|
            |                                                         |
            |--- (1) 查号: mountd 在哪个端口? [基于 ONC RPC] --------->| Port 111
            |<-- (2) 告知: 今天在端口 32768 --------------------------| (Portmapper)
            |                                                         |
            |======= 第二轮:控制面文件挂载 (mountd) ==========================|
            |                                                         |
            |--- (3) 挂载请求: 验证权限并请求目录句柄 -------------------->| Port 32768
            |<-- (4) 挂载成功: 返回根目录的文件句柄 (File Handle) ------| (mountd)
            |                                                         |
            |======= 第三轮:数据面文件读写 (nfsd) ============================|
            |                                                         |
            |--- (5) 读数据: 携带句柄、偏移量、读取长度 ------------------>| Port 2049
            |<-- (6) 返回数据: 传输真实的二进制文件内容 -------------------| (nfsd)
            |                                                         |

    NFSv4

    [ 客户端 (Client) ]                                       [ 服务端 (Server) ]
            |                                                         |        |                                                         |
            |======= 核心控制与数据复合传输 (TCP Single Pipe) =================|
            |                                                         |
            |--- (1) 发送 COMPOUND 复合操作打包报文 -------------------->| Port 2049
            |        |                                                | (nfsd 核心引擎)
            |        +-- [内含操作 1]: PUTROOTFH (定位根句柄)            |
            |        +-- [内含操作 2]: LOOKUP    (寻找路径)             |-- 服务端内核
            |        +-- [内含操作 3]: OPEN/LOCK (打开并加锁)           |   收到处理返回        
            |        +-- [内含操作 4]: READ      (直接读数据)           |   
            |                                                         |   
            |                                                         |
            |<-- (2) 返回 COMPOUND 复合回复报文 ------------------------|
            |        |                                                |
            |        +-- [回复 1]: 状态 NFS4_OK                       |
            |        +-- [回复 2]: 状态 NFS4_OK                       |
            |        +-- [回复 3]: 状态 NFS4_OK (锁定成功)             |
            |        +-- [回复 4]: 状态 NFS4_OK + [真实文件数据]       |
            |                                                         |

    ==总结==:

    1.rpcbind和nfs服务端关系

    核心关系:服务发现与端口映射

    NFS 服务在设计上依赖一种叫做 RPC(远程过程调用) 的通信机制。RPC 服务的一个核心特点是,它们会在系统启动时随机监听一个端口,而不是像 Web 服务那样固定使用 80 或 443 端口。

    这就产生了一个问题:客户端想访问 NFS 共享,但不知道 NFS 服务程序此刻具体开在哪个端口上。rpcbind 就是用来解决这个问题的。

    • rpcbind 的作用:它是一个 RPC 端口映射器。它的任务就是”记住”系统上每个 RPC 服务(比如 NFS 的核心服务 nfsd、挂载服务 mountd 等)所使用的端口号。rpcbind 自身固定占用 111 端口。
    • 工作流程:

    部署顺序与服务启动

    你截图中的机器作为 NFS 服务端,安装和启动服务的正确顺序是固定的:

    1. 先安装 rpcbind,后安装 NFS 服务:因为 NFS 服务运行依赖 rpcbind 环境。
    2. 先启动 rpcbind,后启动 NFS 服务:必须确保 rpcbind 已经在运行,NFS 服务启动时才能成功向它注册端口信息。

    重要补充:NFSv4 的例外情况

    需要注意,有一个重要的例外:NFSv4 版本不再强制依赖 rpcbind。

    因为 NFSv4 协议做了简化,规定所有通信都固定使用 2049 端口,绕过了动态端口映射的过程。因此,如果客户端和服务端都确定只使用 NFSv4,理论上可以不安装或禁用 rpcbind。不过在很多通用教程和传统部署中,为兼容性考虑,仍会默认安装和启动它。


    2. 核心原因:NFS 是“客户端-服务器”架构

    NFS(网络文件系统)在设计上就是明确区分服务端和客户端的,这是由它“通过网络共享文件”的本质决定的。

    • 机器1 (服务端):是数据的实际拥有者。它的任务是把本地磁盘上的目录(/nfsdir)“发布”或“导出”到网络上,并管理访问权限。因此,它需要运行 nfs-server 服务,并维护 /etc/exports 配置文件。
    • 机器2 (客户端):是数据的使用者。它本身没有这些数据,而是通过网络,将服务端共享出来的目录“挂载”到自己的本地目录(/mnt/nfs)下,像一个本地磁盘一样使用它。

    为什么不能都在一台机器上?

    这种分工是为了满足跨机器共享存储的需求。如果都在一台机器上,就失去了 NFS 存在的意义——那只是本机内部的目录操作。

    在一个标准的生产环境中:

    • 服务端(机器1)通常是专门的存储服务器或文件服务器,集中存放数据。
    • 客户端(机器2及更多机器)则通过网络访问这份集中的数据,实现数据共享、统一备份或集中管理。

    3. 客户端和服务端必须是不同的机器

    • 服务端:提供共享目录(192.168.226.6)
    • 客户端:挂载并使用共享目录(192.168.226.7)
    • 虽然可以本机挂载自己(localhost),但实际应用场景都是跨机器

    服务端的 /etc/exports 必须明确标注允许的客户端 IP

    bash

    # 格式:共享目录 允许的客户端IP(权限)
    /nfsshare 192.168.226.7(rw,sync,no_root_squash)
    #           ↑
    #    必须是客户端的真实 IP

    text

    ┌─────────────────────────┐         ┌─────────────────────────┐
    │   NFS 服务器             │         │   NFS 客户端            │
    │   192.168.226.6         │         │   192.168.226.7         │
    │                         │         │                         │
    │  /etc/exports:          │         │  执行挂载命令:          │
    │  /nfsshare 192.168.226.7│◄────────│  mount 192.168.226.6:/nfsshare /mnt/nfs
    │                         │  允许   │                         │
    │  共享目录:/nfsshare    │         │  挂载点:/mnt/nfs       │
    └─────────────────────────┘         └─────────────────────────┘

    Samba实验

    Samba主配置文件

    主配置文件:/etc/samba/smb.conf 帮助参看:man smb.conf

    语法检查: testparm [-v] [/etc/samba/smb.conf]

    [global]
       workgroup = WORKGROUP        # 工作组名称
       server string = Samba Server # 服务器描述
       security = user              # 认证模式
       log file = /var/log/samba/log.%m # 日志文件路径
       max log size = 50            # 最大日志文件大小(KB)
       dns proxy = no               # 禁用 DNS 代理
    
    [shared]
       path = /srv/samba/shared      # 共享路径
       browseable = yes              # 是否可浏览
       writable = yes                # 是否可写
       valid users = @smbgroup       # 允许访问的用户/组

    安装Samba服务

    [root@localhost ~]# yum -y install samba
    [root@localhost ~]# systemctl enable --now smb
    [root@localhost ~]# systemctl enable --now nmb
    [root@localhost ~]# ss -nlt
    State    Recv-Q   Send-Q     Local Address:Port       Peer Address:Port   Process
    LISTEN   0        50               0.0.0.0:445             0.0.0.0:*
    LISTEN   0        50               0.0.0.0:139             0.0.0.0:*
    LISTEN   0        128              0.0.0.0:22              0.0.0.0:*
    LISTEN   0        50                  [::]:445                [::]:*
    LISTEN   0        50                  [::]:139                [::]:*
    LISTEN   0        128                 [::]:22                 [::]:*

    配置Samba用户

    • 包:samba-common-tools
    • 工具:smbpasswd pdbedit
    • 用户数据库:/var/lib/samba/private/passdb.tdb

    说明:samba用户须是Linux用户,建议使用/sbin/nologin

    一、创建系统用户

    [root@localhost ~]# useradd -s /sbin/nologin smbuser
    [root@localhost ~]# echo 123 | passwd --stdin smbuser
    Changing password for user smbuser.
    passwd: all authentication tokens updated successfully.

    二、创建Samba用户

    [root@localhost ~]# smbpasswd -a smbuser
    New SMB password:
    Retype new SMB password:
    Added user smbuser.
    [root@localhost ~]# smbpasswd -e smbuser        # 启用用户
    Enabled user smbuser.

    基于特定用户或组的共享

    服务端操作

    一、创建共享目录

    共享目录为:/data/samba

    [root@localhost ~]# mkdir -p /data/samba
    [root@localhost ~]# chown -R smbuser:smbuser /data/samba
    [root@localhost ~]# chmod -R 2770 /data/samba #任何用户在该目录下新建的文件或子目录,其所属组会自动继承该目录的组,而不是创建者自己的默认组。

    二、添加配置文件

    [root@localhost ~]# vim /etc/samba/smb.conf
    ......
    [shared]
       path = /data/samba
       browseable = yes
       writable = yes
       valid users = @smbuser
       create mask = 0660
       directory mask = 2770

    三、关闭防火墙与SELinux

    [root@localhost ~]# systemctl stop firewalld
    [root@localhost ~]# setenforce 0

    四、重启smb服务

    [root@localhost ~]# systemctl restart smb

    实践

    Windows客户端界面

    image-20260803233859456

    image-20260803233951812

    image-20260803234931956

    image-20260804000208079

    image-20260804000338341


    Linux的smbclient界面

    image-20260804130029308

    ==手动挂载cifs文件系统==:

    image-20260804131906928

    自动挂载(另一种方式):

    开机自动挂载:

    [root@localhost ~]# vim /etc/fstab
    //192.168.226.7/shared  /mnt/smb        cifs    defaults,username=smbuser,password=123 0 0
    [root@localhost ~]# systemctl daemon-reload
    [root@localhost ~]# mount -a
    [root@localhost ~]# df -h
    Filesystem              Size  Used Avail Use% Mounted on
    devtmpfs                4.0M     0  4.0M   0% /dev
    tmpfs                   872M     0  872M   0% /dev/shm
    tmpfs                   349M  5.2M  344M   2% /run
    /dev/mapper/rl-root      17G  1.7G   16G  10% /
    /dev/nvme0n1p1          960M  261M  700M  28% /boot
    //192.168.88.10/shared   17G  1.7G   16G  10% /mnt/smb
    tmpfs                   175M     0  175M   0% /run/user/0

    ==进程实战最终目标==:针对不同用户配置不同访问目录

    服务端

    一、创建并启用用户

    创建三个samba用户,分别为smb1、smb2、smb3。密码均为:123

    [root@localhost ~]# useradd -s /sbin/nologin -r smb1        # -r 不创建家目录
    [root@localhost ~]# useradd -s /sbin/nologin -r smb2
    [root@localhost ~]# useradd -s /sbin/nologin -r smb3
    [root@localhost ~]#
    [root@localhost ~]# smbpasswd -a smb1
    New SMB password:
    Retype new SMB password:
    Added user smb1.
    [root@localhost ~]# smbpasswd -a smb2
    New SMB password:
    Retype new SMB password:
    Added user smb2.
    [root@localhost ~]# smbpasswd -a smb3
    New SMB password:
    Retype new SMB password:
    Added user smb3.
    [root@localhost ~]# smbpasswd -e smb1
    Enabled user smb1.
    [root@localhost ~]# smbpasswd -e smb2
    Enabled user smb2.
    [root@localhost ~]# smbpasswd -e smb3
    Enabled user smb3.
    
    # 查看smb用户
    [root@localhost ~]# pdbedit -L
    smbuser:1000:
    smb2:986:
    smb1:987:
    smb3:985:

    二、修改Samba配置文件如下

    [root@localhost ~]# vim /etc/samba/smb.conf
    # 在global中添加该字段
    [global]
    config file = /etc/samba/conf.d/%U        # 变量%U表示匹配用户名
    
    # 新建共享配置
    [share]
            path = /data/samba/share
            browseable = yes
            writable = yes
            Guest ok = yes
            create mask = 0660
            directory mask = 2770

    三、配置共享目录和文件

    [root@localhost ~]# mkdir -p /data/samba/share
    [root@localhost ~]# mkdir -p /data/samba/smb1
    [root@localhost ~]# mkdir -p /data/samba/smb2
    [root@localhost ~]# touch /data/samba/share/share.txt        # 共享目录及文件
    [root@localhost ~]# touch /data/samba/smb1/smb1.txt            # smb1目录及文件
    [root@localhost ~]# touch /data/samba/smb2/smb2.txt            # smb2目录及文件
    [root@localhost ~]# tree /data/samba/
    /data/samba/
    ├── file.txt
    ├── server2.txt
    ├── share
    │   └── share.txt
    ├── smb1
    │   └── smb1.txt
    └── smb2
        └── smb2.txt
    
    # 将/data/samba目录权限放开
    [root@localhost ~]# chmod 777 -R /data/samba

    四、针对smb1用户和smb2用户单独编辑配置文件

    [root@localhost ~]# vim /etc/samba/conf.d/smb1
    [share]
            path = /data/samba/smb1
            writable = yes
            create mask = 0660
            browseable = yes
    [root@localhost ~]# vim /etc/samba/conf.d/smb2
    [share]
            path = /data/samba/smb2
            writable = yes
            create mask = 0660
            browseable = yes

    五、重启相关服务

    [root@localhost ~]# systemctl restart smb
    [root@localhost ~]# systemctl restart nmb

    image-20260804170327300

    image-20260804170725583

    image-20260804171343174

    image-20260804171543723

    image-20260804171706552

    image-20260804171948688

    在文件末尾或 [global] 段中添加:

    ini [global]

    其他已有配置保持不变…

    # 添加子配置文件目录
    config include = /etc/samba/conf.d/%U        # 这会让samba自己加载conf.d目录以smb{1,2,3}为名字的子配置文件这会让 Samba 自动加载 /etc/samba/conf.d/ 目录下所有 用户名匹配的子配置文件。

    修改主配置文件,增加共享路径 同样在 /etc/samba/smb.conf 中,在文件末尾添加一个公共共享:

    对smb1用户和smb2用户单独编辑配置文件

    [root@localhost ~]# vim /etc/samba/conf.d/smb1
    [share]
            path = /data/samba/smb1
            writable = yes
            create mask = 0660
            browseable = yes
    [root@localhost ~]# vim /etc/samba/conf.d/smb2
    [share]
            path = /data/samba/smb2
            writable = yes
            create mask = 0660
            browseable = yes

    五、重启相关服务

    [root@localhost ~]# systemctl restart smb

    ==注意==:==生效的是配置文件里的路径,开头的global,print,share标识符只是为了人类可读区分·无任何意义==

    实际出现问题

    image-20260804182431966

    image-20260804182446627

    配置中有这两行:

    ini

    valid users = @smbuser
    Guest ok = yes

    这两行是冲突的,而且 valid users = @smbuser 优先级更高。实际效果是:

    • Guest ok = yes 被忽略了
    • 只有属于 smbuser 用户组的用户才能访问
    • 你的 smb1 用户不在 smbuser 组中,所以被拒绝访问

    image-20260804183347706

    image-20260804183403233

    ==生产环境总结==

    text

    ╔═══════════════════════════════════════════════════════════════════╗
    ║                    Samba 生产环境架构图                           ║
    ╚═══════════════════════════════════════════════════════════════════╝
    
    ┌─────────────────┐  ┌─────────────────┐  ┌─────────────────────┐
    │   开发人员 PC    │  │   运维人员 PC    │  │   应用服务器集群     │
    │   (Windows)     │  │   (Linux/Mac)   │  │   (Linux)           │
    ├─────────────────┤  ├─────────────────┤  ├─────────────────────┤
    │ • 写代码        │  │ • 部署应用      │  │ • 读取配置          │
    │ • 编译打包      │  │ • 查日志排障    │  │ • 写日志            │
    │ • 改配置        │  │ • 备份恢复      │  │ • 共享静态资源      │
    └────────┬────────┘  └────────┬────────┘  └──────────┬──────────┘
             │                    │                       │
             │  映射网络驱动器    │  mount 挂载           │  mount/挂载
             │  (Z:/X:/)         │  (smbclient)          │  (cifs/nfs)
             └────────┬───────────┴───────────────────────┘
                      │
                      ▼
             ╔═══════════════════════════════════════════╗
             ║         Samba 服务器 (192.168.226.7)      ║
             ╠═══════════════════════════════════════════╣
             ║  /data/samba/                            ║
             ║  ├── deploy/      ← 部署包中转站         ║
             ║  ├── config/      ← 配置中心             ║
             ║  ├── logs/        ← 日志汇聚             ║
             ║  ├── backup/      ← 备份存储             ║
             ║  └── exchange/    ← 跨系统数据交换       ║
             ╚═══════════════════════════════════════════╝
                      │
                      ▼
             ┌─────────────────────────────────────────────┐
             │         异地备份 / 对象存储归档              │
             │   (定时同步到 OSS / 异地机房 / 磁带库)      │
             └─────────────────────────────────────────────┘
    
    
    ═══════════════════════════════════════════════════════════════════════
    
    【数据流向说明】
    
    ① 开发 → Samba      : 上传部署包、修改配置文件
    ② 运维 → Samba      : 拉取部署包、查看日志、备份数据
    ③ Samba → 应用服务器 : 应用启动时读取配置、运行时写日志
    ④ 应用服务器 → Samba : 日志回写、数据交换
    ⑤ Samba → 异地备份   : 定期归档到灾备中心
    
    ═══════════════════════════════════════════════════════════════════════
  • Linux的存储管理

    补充信息

    ​

    1.blkid命令可以方便查看uuid
    2.gpt所有分区都是平等的,没有区分,parted命令需要输入primary是历史遗留问题,mbr有主分区,最多4个,如果使用扩展分区,可以分出多个
    3.mb和mib是有区别的,mb进制1000,mib进制1024
    4.parted /dev/sda align-check opt 1  #检查分区标号为1的分区,是否满足optimal对齐,(起止扇区是2048的倍数,1mib对齐),如果输出1 aligned   代表 ✅ 通过最优标准
    5.分区可以使用%,这样便于parted自动处理对齐,提高读写性能
    

    [root@localhost ~]# parted /dev/sda mkpart primary 0% 10%
    信息: 你可能需要 /etc/fstab。
    
    [root@localhost ~]# parted /dev/sda mkpart primary 10% 20%
    信息: 你可能需要 /etc/fstab。
    
    [root@localhost ~]# parted /dev/sda mkpart primary 20% 30%
    信息: 你可能需要 /etc/fstab。
    
    [root@localhost ~]# parted /dev/sda mkpart primary 30% 40%
    信息: 你可能需要 /etc/fstab。
    
    [root@localhost ~]# parted /dev/sda mkpart primary 40% 50%
    错误: 无法创建更多分区。
    
    6.Linux 内核中,每个磁盘块设备最多只预留 16 个分区号
    7.如果需要当作系统盘启动系统,必须分区;如果仅当作普通磁盘使用,并不需要分区
    8.mount注意挂在参数,默认是是rw,如果仅仅想只读挂载
    # 只读挂在
    mount -o ro /dev/sda1 /mnt/data
    # 不用卸载,直接切换为只读
    mount -o remount,ro /mnt/data

    ==总结==:image-20260721200137473

    image-20260721200302621

    存储管理

    硬盘工作原理

    image-20260721152056322 image-20260721152124554

    image-20260721152154862

    image-20260721152210844

    image-20260721152236951


    ==总结==:

    安装操作系统时硬盘确实必须分区。简单来说,新硬盘就像一张白纸,需要划分区域(分区)并建立目录(文件系统),电脑才能识别和使用它。

    这个过程主要有两步:一是制作一个能启动电脑的启动盘,二是进入安装环境后对硬盘进行手动分区

      • GPT(GUID Partition Table):现代电脑的首选。它搭配**UEFI** 启动模式,支持2TB以上大硬盘、分区数量不受限且更稳定。
      • MBR (Master Boot Record):老标准。搭配传统 Legacy BIOS 模式,有诸多限制。

    现在绝大多数新电脑都默认UEFI+GPT模式,请优先选择。

    1. 安装界面中的分区操作
      选择好分区表后,就可以在安装界面进行分区了。一个典型的Windows分区方案通常包含:

    EFI系统分区 (ESP):必须创建。用于存放电脑启动所必需的文件。在GPT分区方案中,这是系统能够正常启动的前提。通常约 100-500 MB,格式为 FAT32。

    系统分区 (C盘):用于安装操作系统和应用程序。建议容量不低于 120 GB,如果硬盘空间充裕,150-200 GB 会更从容。格式为 NTFS。

    数据分区 (D盘、E盘等):用于存放个人文件、文档、照片、视频等。在安装系统时,可以只创建C盘,剩余空间留待系统安装完成后,再通过系统自带的“磁盘管理”工具来划分。这样做的好处是,将来重装系统时,只需格式化C盘,其他盘的数据不受影响。*

    1. 关于“激活分区”
      这是一个常见误解。“激活分区”是MBR磁盘时代的操作。在目前主流的GPT+UEFI模式下,系统通过EFI系统分区(ESP) 来引导启动,完全不需要手动去“激活”任何分区。错误地激活分区反而可能导致系统无法启动。

总结

总的来说,安装系统时分区是必须的。核心流程是:

制作一个匹配你电脑启动模式(UEFI)的启动U盘。

进入安装界面后,为硬盘选择GPT分区表。

创建EFI系统分区(ESP)和一个足够大的C盘。

将系统安装到C盘。

系统装好后,再用“磁盘管理”工具把剩下的空间分成D盘、E盘。

  1. U盘启动安装操作系统

image-20260722192104443

image-20260721152256900

image-20260721152318186image-20260721152354689

fdisk和parted区别

image-20260723091814533

==先用fdisk就行,忽视第二种==


fdisk实践复现

image-20260723093046470

image-20260723093230929


image-20260721152410849


文件系统

image-20260721152500121

==注意==:你笔记里写 Ext4支持1EB,XFS支持18EB。1 EB = 1024 PB = 100万 TB。实际上你根本碰不到这个天花板,可以忽略不计。


image-20260721152542391

==总结==:

image-20260723102456401

日常干活:闭眼敲mkfs.xfs /dev/sdX,系统自动给你生成最优的superblock/inode/block,VFS在底层无缝衔接。


image-20260721152604018

image-20260721152621722

挂载和永久挂载

image-20260723112104182

image-20260723114045833


image-20260721152637412

卸载挂载

image-20260723114511451


==总结==:

挂载新盘是 Linux 存储管理中实现“数据与操作系统物理隔离”的唯一手段。系统盘仅负责维护 OS 运行环境与基础软件包,而所有可增长的用户数据、业务持久化数据及高频日志,必须通过挂载独立文件系统的方式存放到额外物理磁盘,以此确保系统稳定性、数据安全性及存储资源的弹性扩展。


image-20260721152657596

swap分区操作

image-20260723131357070

image-20260723130015847


磁盘配额

image-20260721152719546

image-20260721152732607

Linux磁盘配额

image-20260724075630274

image-20260724075711441

==总结==:

image-20260724080055177

image-20260724080135354


image-20260721152746714

image-20260721152800528

==总结==:

image-20260724083557674

image-20260724083621966

image-20260724083712549

image-20260724083859548

注意: image-20260724083943772

Nas存储

image-20260724085639468

Raid磁盘阵列和逻辑卷

raid存储和逻辑卷

​ 1. nas介绍

​ 2. Set-A 和 Set-B 的含义

在 RAID 10 中,数据是先镜像(RAID 1),再条带(RAID 0)。set-A 和 set-B 代表了 两个不同的镜像组:

Set-A:包含 /dev/nvme0n2 和 /dev/nvme0n4,这两块盘互为镜像,数据完全一致。

Set-B:包含 /dev/nvme0n3 和 /dev/nvme0n5,这两块盘互为镜像,数据完全一致。

工作逻辑:

写入数据时,系统会把数据分成两份(条带化),一份写在 Set-A,另一份写在 Set-B。

在 Set-A 内部,数据会同时写入nvme0n2 和 nvme0n4(镜像)。

在 Set-B 内部,数据会同时写入nvme0n3 和nvme0n5(镜像)。

​ 3. 也可以用proc目录下实时运行数据查看

[root@localhost ~]# cat /proc/mdstat

Personalities : [raid10]

md127 : active (auto-read-only) raid10 nvme0n5[3] nvme0n3[1] nvme0n4[2]

​ 41908224 blocks super 1.2 512Kchunks 2 near-copies [4/3] [_UUU]

​ bitmap: 1/1 pages [4KB,65536KB chunk

​ 4. raid5说明

假设这一条”数据带(stripe)”是这样分布的:

盘1: 1101   (数据A)
盘2: 1011   (数据B)
盘3: 0110   (校验P = A XOR B)

这里 P = 1101 XOR 1011 = 0110,正好对上。

场景:盘2 挂了

阵列里少了”数据B”这一块,但盘1(数据A)和盘3(校验P)都还在。

恢复公式:

数据B = 数据A XOR 校验P
      = 1101 XOR 0110
      = 1011   ← 和原来的盘2数据完全一致!

场景:盘3(校验盘那部分)挂了

因为数据A、数据B本身都还在,校验值只是”备份用”的,直接:

新的P = 数据A XOR 数据B = 1101 XOR 1011 = 0110

重新算一遍填回新盘就行,不涉及”恢复”,只是”重建校验”。

实际重建流程:

把坏盘换成新盘(热备盘或者手动换盘)

RAID 控制器/软件(比如 mdadm)会逐条(stripe)地对剩余盘做 XOR 运算

把算出来的结果写入新盘对应位置,这个过程叫 rebuild,好几 TB 的盘全部重建往往要花几个到十几个小时,而且期间会持续大量读取剩余盘,这也是为什么”重建期间再坏一块盘”是 RAID 5 最大的风险点,你的盘越大,这个风险窗口就越长。

逻辑卷

​ 1. 物理卷pv处于 LVM中的最底层,可以将其理解为物理磁盘、磁盘分区或者 RAID 磁盘阵列。

​ 2. vgcreate中的路径是pv的名字,而pv的名字必须是物理磁盘设备路径,分区路径,raid路径

​ 3. vmvare的rockylinux默认系统盘就是基于pv的,默认分区是MBR分区

逻辑卷设备路径,两种路径都可以用来挂载,大家根据喜好来

  1. /dev/mapper/路径(内核设备映射器路径)

这是 Linux 内核设备映射器(Device Mapper) 创建的真实设备节点

格式:/dev/mapper/VGname-LVname

特殊字符(如 -)会被转义为 –(双横线)

例如:VG=pjw-storage,LV=lt-pjw → /dev/mapper/pjw--storage-lt--pjw

  1. /dev/VGname/LVname路径(LVM软链接)

这是 LVM工具包(lvm2) 创建的符号链接(软链接)

格式:/dev/VGname/LVname

更加直观易读,没有字符转义

例如:/dev/pjw-storage/lt-pjw

​ 3. 可以使用如下命令查找dmpath

[root@192 mnt]# lvs -o lv_name,vg_name,lv_path,lv_dm_path
  LV        VG          Path                       DMPath
  extra-pjw pjw-storage /dev/pjw-storage/extra-pjw /dev/mapper/pjw--storage-extra--pjw
  lt-pjw    pjw-storage /dev/pjw-storage/lt-pjw    /dev/mapper/pjw--storage-lt--pjw
  home      rlm         /dev/rlm/home              /dev/mapper/rlm-home
  root      rlm         /dev/rlm/root              /dev/mapper/rlm-root
  swap      rlm         /dev/rlm/swap              /dev/mapper/rlm-swap

​

==总结==:

能直接使用的硬件(硬盘、分区、RAID 阵列)都能作为 LVM 的物理卷 PV,然后 PV合并成卷组 VG,再从 VG 里切出逻辑卷 LV 来用。

path 和 dmpath 的本质关系

text

/dev/rlm/root          ← path(LVM 提供的软链接)
        ↓ 指向
/dev/mapper/rlm-root   ← dmpath(内核 device-mapper 真实设备节点)
        ↓ 对应
Block device 253:0     ← 内核块设备号(你截图里有)
        ↓ 挂载到
/                       ← 挂载点(目录名)

结论:path 和 dmpath 指向同一个东西,只是表现形式不同。你用 ls -l /dev/rlm/root 就能看到它是一个软链接,指向 /dev/dm-0(或 /dev/mapper/rlm-root)。


✅ 你现在应该怎么理解

  • 挂载时用哪个都行:mount /dev/rlm/root /mnt 和 mount /dev/mapper/rlm-root /mnt 效果完全一样。
  • 挂载路径就是目录名:你说得对,挂载点就是一个目录(如 /、/home),用来“接入”存储设备。

扩缩容

先扩逻辑卷,再扩文件系统

先缩文件系统,再缩逻辑卷

快照逻辑卷

应用场景,我需要备份某个应用数据,应用数据所在盘是基于逻辑卷管理的,便可以使用快照来操作

​ 1. 创建一个与需要备份的逻辑卷相同大小的快照逻辑卷

​ a. 创建过程很快,因为是CoW技术,本质这个逻辑卷记录的是从创建快照结点之后与目标盘的变化

​ b. 如果目标盘损坏,快照就没了,因此此操作不是备份

​ 2. 只读挂载逻辑卷,可以将其数据copy至其他盘

lsof /mnt/lvol0

fuser -mv /mnt/lvol0

实践

image-20260724154431789

image-20260724154459908

命令大全

# 部署lv
pvcreate /dev/nvme0n2 /dev/nvme0n3 # 设备号
vgcreate storage /dev/nvme0n2 /dev/nvme0n3  # storage 是vg名称,自定义;/dev/nvme0n2是pv name
lvcreate -n vo -L 120mb storage   # -n指定lv名称, -L指定单位大小, storage,从vg名为storage的vg中划分
lvdisplay  #查看lv挂载path:   /dev/storage/vo
mkfs.ext4 /dev/storage/vo  # 格式化位ext4
mkdir /mnt/vo #创建挂载点
mount /dev/storage/vo /mnt/vo # 挂载
df -Th #查看信息

# 扩容(先扩lv,再扩文件系统)
umount /mnt/vo
lvextend -L 290M /dev/storage/vo  #也可以使用+290m代表增加290m,如果是290m代表扩容至290m
e2fsck -f /dev/storage/vo  #检查文件系统,此工具用于检查ext3/4文件系统,-f参数强制检查
resize2fs /dev/storage/vo   #用于扩容ext3/4文件系统
mount /dev/storage/vo /mnt/vo # 挂载
df -Th  #查看

# 缩容(先缩文件系统,再缩lv)
umount /mnt/vo
e2fsck -f /dev/storage/vo
resize2fs /dev/storage/vo 120M   #文件系统缩至120m
lvreduce -L 120M /dev/storage/vo  #lv缩至120m
mount /dev/storage/vo /mnt/vo # 挂载
df -Th  #查看

#快照
echo "hello world" > /mnt/vo/hello.txt  # 写入点文件在逻辑卷中
lvcreate -L 120M -s -n snap /dev/storage/vo  # 创建/dev/storage/vo的快照卷,-s代表创建扩招卷,-n快照卷名称
dd if=/dev/zero of=/mnt/vo/files count=1 bs=50M  # 往/mnt/vo/files写入50m文件,观察snap逻辑卷中的Allocated to snapshot行
mkdir /mnt/snap
mount -o ro /dev/storage/snap /mnt/snap
ls -l /mnt/snap
cat /mnt/snap/hello.txt
# 使用快照还原
ls -l /mnt/storage/vo
umount /mnt/snap
umount /mnt/vo
lvconvert --merge /dev/storage/snap
mount /dev/storage/vo /mnt/vo # 此时近剩hello.txt文件
lvdisplay  # /dev/storage/snap也没了

# 删除逻辑卷
1.先umount所有设备
2.先删除lv
3.在删除vg
4.最后删除pv

# 给虚拟机/目录(根目录)扩容
pvcreate /dev/nvme0n6
vgdispaly
vgextend rlm /dev/nvme0n6  # 给vg扩容
df -Th  #找出/目录(根目录)对应的挂载设备
lvdisplay /dev/mapper/rlm-root
lvextend -L +20G /dev/rlm/root  # lvextend -l +100%FREE /dev/rlm/root #给vg中所有空间
xfs_growfs /
df -Th

==实践==:

image-20260726142022444

image-20260726142034037

image-20260726143647724

image-20260726143703613

==区别==:

image-20260726153920374

image-20260726153936867


xfs系统新特性

xfs_repair -n block-device  # 检查xfs文件系统,无副作用,但是要求umount block-device
# 10.1版本后,提供了xfs_scrub,可支持在线检查,但注意检查都会占用机器性能

Rocky Linux 10.1 Available Now – Rocky Linux

You can now scrub mounted XFS filesystems with xfs_scrub and shrink XFS filesystems with xfs_growfs in some scenarios.

9.7中xfs_scrub在xfsprogs-xfs_scrub包中提供了,但是是实验特性,可以体验一下

==总结==:

image-20260724103502731

image-20260724152449508

  • Linux的Nginx

    功能

    • 静态的web资源服务器 HTML,image,js,CSS,txt 等静态资源
    • 结合 FastCGI/uWSGI/SCGI 等协议反向代理动态资源请求
    • HTTP/HTTPS 协议的反向代理
    • imap4/pop3 协议的反向代理
    • TCP/UDP 协议的反向代理

    基本特征

    • 模块化设计,较好的扩展性
    • 高可靠性高性能高于 Apache
    • 支持热部署:不停机更新配置文件,升级版本,更换日志文件
    • 低内存消耗:10000个 keep-alive 连接模式下的非活动连接,仅需2.5M内存
    • 事件驱动epoll,异步非阻塞IO,内存映射等等特性

    Nginx 基础

    对于 Nginx 的安装,我们常用的方法为在线安装和源码包编译安装

    其中:

    • yum 下载的相关文件都是放在默认的位置,简单高效
    • 编译安装可以自定义版本和功能,更适合业务的定制化

    YUM 安装

    # 安装
    [root@localhost ~]# yum provides nginx
    [root@localhost ~]# yum install nginx -y
    # 启动
    [root@localhost ~]# systemctl start nginx && systemctl enable nginx
    # 关闭防火墙和SELINUX
    # 测试
    [root@localhost ~]# curl -I 127.0.0.1
    HTTP/1.1 200 OK
    Server: nginx/1.20.1

    相关文件

    文件 说明
    /etc/nginx/nginx.conf 主配置文件
    /var/log/nginx/ 日志文件目录
    /usr/share/nginx/html/ 默认站点根目录
    /usr/lib/systemd/system/nginx.service Systemd服务文件
    /var/run/nginx.pid 主进程ID文件
    /usr/share/nginx/modules 动态加载模块目录
    /etc/nginx/conf.d/ 子配置文件目录

    主配置文件(/etc/nginx/nginx.conf)

    image-20260818165715944

    CPU亲和性设置

    worker_processes 8; # 指定 8 个 worker 进程

    worker_cpu_affinity 00000001 00000010 00000100 00001000 00010000 00100000 01000000 10000000;

    这段配置是 Nginx 中针对多核 CPU 服务器进行的核心性能优化。它通过手动绑核,确保每个 Nginx 工作进程(Worker)独占一个 CPU 核心。

    下面我来逐行拆解:

    1. worker_processes 8;

    • 含义:启动 8 个 Nginx 工作进程。
    • 背景:Nginx 采用事件驱动+异步非阻塞模型,通常建议将 Worker 数量设为 CPU 核心数(这里是 8 核),以充分利用多核并行处理能力。

    2. worker_cpu_affinity 00000001 ... 10000000;

    • 含义:将 8 个 Worker 进程分别绑定到 8 个不同的 CPU 核心上运行。
    • 核心作用:防止 CPU 缓存频繁失效(避免进程在不同核心间“跳跃”),提升 CPU 缓存命中率,从而降低延迟并提高吞吐量。

    3. 掩码(Mask)深度解析

    配置中的 00000001 等是 CPU 亲和性掩码,采用二进制位图表示。

    规则:从右向左读取,第 N 位(从 0 开始)为 1,代表允许该 Worker 运行在第 N 号 CPU 核心上。

    Worker 序号 掩码 (二进制) 对应核心 (从右往左数)
    第 1 个 00000001 CPU 0
    第 2 个 00000010 CPU 1
    第 3 个 00000100 CPU 2
    第 4 个 00001000 CPU 3
    第 5 个 00010000 CPU 4
    第 6 个 00100000 CPU 5
    第 7 个 01000000 CPU 6
    第 8 个 10000000 CPU 7

    主配置文件内容

    [root@localhost ~]# grep -Ev '^$|^#|s*#' /etc/nginx/nginx.conf
    # 全局配置块
    ## 运行用户
    user nginx;
    ## 工作进程数
    worker_processes auto;  # 默认就是八个
    ## 错误日志
    error_log   /var/log/nginx/error.log;
    ## pid文件存放位置
    pid    /run/nginx.pid;
    ##  动态加载模块配置
    include   /usr/share/nginx/modules/*.conf;
    # events配置块
    events {
        # 设置单个工作进程最大并发连接数
        worker_connections 1024;
    }
    # http配置块
    http {
        ## 日志格式定义
        log_format  main  '$remote_addr - $remote_user [$time_local] "$request" '
                          '$status $body_bytes_sent "$http_referer" '
                          '"$http_user_agent" "$http_x_forwarded_for"';
        ## 访问日志
        access_log  /var/log/nginx/access.log  main;
        ## 启用 sendfile() - 利用操作系统内核的零拷贝技术:即数据拷贝无需切换至用户空间
        sendfile            on;
        ## 启用 TCP_NOPUSH - 优化网络包传输:即数据包填满时发送
        tcp_nopush          on;
        ## 启用  TCP_NODELAY - 减少延迟:即基于keepalive连接,尽快发送小数据包
        tcp_nodelay         on;
        ## keepalive 超时时间
        keepalive_timeout   65;
        ## 设置用于存储MIME类型映射的哈希表最大大小
        types_hash_max_size 4096;
        ## 定义文件扩展名与MIME类型的映射
        include             /etc/nginx/mime.types;
        ## 定义响应包默认MIME类型
        default_type        application/octet-stream;
        ## 加载子配置文件
        include /etc/nginx/conf.d/*.conf;
        # server配置块
        server {
            ## 监听ipv4和ipv6 80端口
            listen       80;
            listen       [::]:80;
            ## 定义虚拟主机的名称-域名
            server_name  _;
            ## 根目录
            root         /usr/share/nginx/html;
            ## 加载默认站点子配置文件
            include /etc/nginx/default.d/*.conf;
            ## 定义错误页
            error_page 404 /404.html;
            # location配置块
            location = /404.html {
            }
            error_page 500 502 503 504 /50x.html;
            location = /50x.html {
            }
        }
    }
    
    # 默认配置文件不包括下面两个块
    # mail协议相关配置段
    mail {
      ...
    }
    # stream服务器相关配置段
    stream {
      ...
    }

    虚拟主机(就是后端网站)

    基于不同的IP、不同的端口以及不同的域名实现不同的虚拟主机,依赖于核心模块 ngxhttp core_module 实现

    案例分析

    • 定义 PC 站点,根目录为 /data/nginx/site01,直接通过 x.x.x.x:8001
    • 定义 Mobile 站点,根目录为 /data/nginx/site02,通过自定义域名访问
    • 定义 Test 站点,根目录为 /data/nginx/site03, 仅能通过本地 127.0.0.1:8003 访问
    • 定义 Test 站点,访问 127.0.0.1:8003/status,根目录为 /data/nginx
    [root@localhost ~]# mkdir -pv /data/nginx/site0{1..3}/
    [root@localhost ~]# mkdir -pv /data/nginx/status
    [root@localhost ~]# echo "Running 3 websites" > /data/nginx/status/index.html
    [root@localhost ~]# echo "Hello PC Website!" > /data/nginx/site01/index.html
    [root@localhost ~]# echo "Hello Moblie Website!" > /data/nginx/site02/index.html
    [root@localhost ~]# echo "Hello Local Test Website!" > /data/nginx/site03/index.html
    [root@localhost ~]# cat << EOF > /etc/nginx/conf.d/vhost.conf
    # PC
    server {
        listen  8001;
        location  / {
            root  /data/nginx/site01;
        }
    }
    # Mobile
    server {
        listen 80;
        server_name m.test.com;
        location / {
            root /data/nginx/site02;
        }
    }
    # Test
    server {
        listen 127.0.0.1:8003;
        location / {
            root /data/nginx/site03;
        }
        location /status {
            root /data/nginx;  
        }
    }
    EOF
    # 检查配置文件并重新加载
    [root@localhost ~]# nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    [root@localhost ~]# nginx -s reload
    # 测试验证
    [root@localhost ~]# curl 192.168.226.128:8001
    Hello PC Website!
    [root@localhost ~]# curl -H 'Hostname: p.test.com' 192.168.226.128
    Hello Moblie Website!
    [root@localhost ~]# curl 192.168.226.128:8003
    curl: (7) Failed to connect to 192.168.226.128 port 8003: Connection refused
    # 定义 location 时:文件的绝对路径等于 root+location
    [root@localhost ~]# curl -L 127.0.0.1:8003/status
    Running 3 websites

    1. 配置文件逐段详解

    这个文件定义了三个独立的 server 块(虚拟主机),分别监听不同的端口或域名。


    第一部分:PC 网站

    nginx

    # PC
    server {
        listen  8001;
        location  / {
            root  /data/nginx/site01;
        }
    }
    • 监听:所有 IP 地址的 8001 端口。
    • 逻辑:只要访问服务器的 8001 端口,无论用什么域名,都会命中这个块。
    • 根目录:root 指定了文件系统的绝对路径。当你访问 http://IP:8001/ 时,Nginx 会去 /data/nginx/site01/ 下找 index.html。
    • 验证:你的第一个 curl 192.168.226.128:8001 成功,就是因为匹配到了这里。

    第二部分:Mobile 网站(域名虚拟主机)

    nginx

    # Mobile
    server {
        listen 80;
        server_name m.test.com;
        location / {
            root /data/nginx/site02;
        }
    }
    • 监听:默认的 HTTP 端口 80。
    • 关键点:server_name m.test.com。这意味着只有 HTTP 请求头中的 Host 字段为 m.test.com 时,才会进入这个块。
    • 验证:你的第二个 curl -H 'Hostname: p.test.com' 192.168.226.128 使用了自定义请求头,返回了 Hello Moblie Website!,说明命中了该配置并正确返回了 site02 的内容。

    第三部分:Test 网站(本地回环限制)

    nginx

    # Test
    server {
        listen 127.0.0.1:8003;
        location / {
            root /data/nginx/site03;
        }
        location /status {
            root /data/nginx;  
        }
    }
    • 监听:127.0.0.1:8003。
      • 重点:这里指定了具体的 IP 地址 127.0.0.1(即 localhost),而没有像前两个那样写 listen 80(默认代表 0.0.0.0,即所有网卡)。
      • 结果:这个服务只监听在本地环回接口上,不对外网的网卡(如 192.168.226.128)开放。
  • 根目录与 Location 匹配:
  • 命中网站

    1. 第一个端口网站

    image-20260818191230896

    1. 第二个在 linux 上用域名访问

    ​ image-20260819084451941

    3.本地环回网站访问

    image-20260819085348031

    1. 重定向访问

    image-20260819090218420

    关于 -L 参数

    您问的 -L 在 curl 命令中是指:

    bash

    curl -L 127.0.0.1:8003/status
    参数 含义
    -L 跟随重定向(Follow Redirects)

    具体作用:

    为什么设计成这样?

    工具 设计理念
    浏览器 用户体验优先,自动完成跳转
    curl 精确调试优先,让开发者看到完整的 HTTP 交互过程(包括状态码、响应头等)

    curl 不加 -L 的目的是让您看到原始响应,方便调试重定向逻辑。如果需要自动跳转,手动加 -L 即可。


    Location

    Nginx 的 location 指令是配置请求路由的核心机制,其匹配规则基于 URI 和修饰符,优先级由匹配类型和顺序共同决定。

    匹配类型与语法

    location [ = | ~ | ~* | ^~ ] uri { ... }
    修饰符 匹配类型 语法示例 说明
    = 精确匹配 location = /path 仅当 URI 完全等于 /path 时匹配,优先级最高
    ^~ 前缀匹配 location ^~ /images/ 匹配以 /images/ 开头的 URI,停止后续正则检查
    ~ 正则匹配 location ~ .php$ 区分大小写,正则表达式匹配,按配置文件顺序匹配
    ~* 正则匹配 location ~* .(jpg,png)$ 不区分大小写,正则表达式匹配,按配置文件顺序匹配
    无修饰符 前缀匹配 location /static/ 匹配以 /static/ 开头的 URI,需继续正则检查
    / 通用匹配 location / 匹配所有请求,优先级最低

    优先级:= ^~ ~/~* 无修饰符 /

    ==匹配规则可以ai辅助写出来,不用自己记==


    访问控制

    Nginx 的访问控制是保障服务器安全的核心机制,通过多种方式精细化管控请求入口

    基于 IP

    典型场景

    # 黑名单:默认允许,拒绝特定IP
    location /admin {
        deny 192.168.226.128;  # 拒绝单个 IP
        deny 10.0.0.0/8;     # 拒绝网段
        allow all;           # 允许其他 IP
    }
    
    # 白名单:默认拒绝,允许可信IP
    location /api {
        allow 192.168.1.0/24;  # 允许网段
        allow 172.16.1.1;      # 允许单个 IP
        deny all;              # 拒绝其他
    }

    基于 HTTP 认证

    典型场景

    # 生成密码文件
    ## 首次创建
    htpasswd -c /etc/nginx/.htpasswd admin
    ## 追加用户
    htpasswd -c /etc/nginx/.htpasswd root
    
    # 后台管理
    location /admin {
        auth_basic "Tip: input password!";                 # 认证提示语
        auth_basic_user_file /etc/nginx/.htpasswd;   # 密码文件路径
    }

    案例分析

    仅能够通过 admin 用户本地访问后台管理,其他所有IP和用户均不允许

    # 准备实验环境
    [root@localhost ~]# htpasswd -c /etc/nginx/.htpasswd admin
    New password:
    Re-type new password:
    Adding password for user admin
    [root@localhost ~]# mkdir -pv /data/nginx/site04/admin
    [root@localhost ~]# echo "site04" > /data/nginx/site04/admin/index.html
    [root@localhost ~]# cat << EOF > /etc/nginx/conf.d/site04.conf
    server {
        listen  8004;
        # 精细化控制:基于请求属性
        if ($http_user_agent ~* bot) {
            return 403;
        }
        location  /admin {
            root  /data/nginx/site04;
            auth_basic "Tip: input password!";
            auth_basic_user_file /etc/nginx/.htpasswd;
            allow 127.0.0.1;
            deny all;
        }
    }
    EOF
    [root@localhost ~]# nginx -t
    nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
    nginx: configuration file /etc/nginx/nginx.conf test is successful
    [root@localhost ~]# nginx -s reload
    # 测试验证
    client01 ~ % curl -I 172.16.175.129:8004/admin
    HTTP/1.1 403 Forbidden
    [root@localhost ~]# curl -u admin:123 http://127.0.0.1:8004/admin/
    site04
    [root@localhost ~]# curl -I -u root:123 http://127.0.0.1:8004/admin/
    HTTP/1.1 401 Unauthorized
    ## 模拟 bot 访问
    [root@localhost ~]# curl -I -u root:123 -H 'User-agent: bot' http://127.0.0.1:8004/admin/
    HTTP/1.1 403 Forbidden

    实验目标

    搭建一个带有访问控制和密码认证的 Nginx 站点:


    第一步:创建密码文件

    bash

    htpasswd -c /etc/nginx/.htpasswd admin

    逐词拆解:

    部分 含义
    htpasswd Apache HTTP 服务器自带的密码生成工具(Nginx 也使用它)
    -c create,创建新文件(如果文件已存在会覆盖)
    /etc/nginx/.htpasswd 密码文件的存放路径(.htpasswd 是约定俗成的文件名)
    admin 要创建的用户名

    交互过程:

    text

    New password:          # 输入密码(比如 123)
    Re-type new password:  # 再次输入确认
    Adding password for user admin  # 创建成功

    生成的文件内容:

    bash

    cat /etc/nginx/.htpasswd
    # 输出类似:admin:$apr1$random...(加密后的密码)

    image-20260819104618741

    image-20260819104648116

    第 3 行:# 精细化控制,防止爬虫:基于请求属性

    部分 含义
    # 注释符,这一行只是给人看的说明,Nginx 不执行

    作用:告诉阅读配置文件的人,下面这段代码是用来防止爬虫的。


    第 4-6 行:if ($http_user_agent ~* bot) { return 403; }

    nginx

    if ($http_user_agent ~* bot) {
        return 403;
    }
    部分 含义
    if 条件判断语句
    $http_user_agent Nginx 内置变量,存储客户端的 User-Agent(浏览器标识)
    ~* 正则匹配修饰符:~* 表示不区分大小写匹配
    bot 要匹配的关键词(如 Googlebot、Baiduspider)
    return 403 返回 HTTP 状态码 403 Forbidden(禁止访问)

    通俗理解:

    text

    如果 客户端的 User-Agent 中包含 "bot"(不区分大小写)
        那么 直接返回 403 禁止访问

    第 9 行:auth_basic "Tip: input password!";

    部分 含义
    auth_basic 开启 HTTP 基本认证(弹出用户名密码输入框)
    "Tip: input password!" 认证对话框显示的提示文字

    浏览器效果:

    text

    ┌──────────────────────────────┐
    │  需要身份验证                  │
    │  Tip: input password!         │
    │  用户名: [__________]         │
    │  密码:  [__________]         │
    │  [确定]  [取消]               │
    └──────────────────────────────┘

    第 10 行:auth_basic_user_file /etc/nginx/.htpasswd;

    部分 含义
    auth_basic_user_file 指定存放用户名和密码的文件路径
    /etc/nginx/.htpasswd 密码文件的位置

    密码文件内容(用 htpasswd 命令生成):

    text

    admin:$apr1$abc123$xyz789...   ← 加密存储的密码

    第 11 行:allow 127.0.0.1;

    部分 含义
    allow 允许特定 IP 访问
    127.0.0.1 本地回环地址(只有本机能访问)

    通俗理解:只允许本机(127.0.0.1)访问这个目录。


    第 12 行:deny all;

    部分 含义
    deny 拒绝特定 IP 访问
    all 所有 IP 地址

    执行逻辑:

    text

    先检查 allow 127.0.0.1 → 如果是 127.0.0.1,放行
    再检查 deny all → 如果不是 127.0.0.1,拒绝

    结果:只有 127.0.0.1 能访问,其他 IP 全部被拒绝。

    image-20260819110914905

    四个测试命令讲解

    测试 1:外部 IP 访问 → 403 Forbidden

    bash

    [root@localhost ~]# curl 192.168.226.128:8004/admin -I
    HTTP/1.1 403 Forbidden
    Server: nginx/1.20.1
    Date: Wed, 19 Aug 2026 02:58:02 GMT
    Content-Type: text/html
    Content-Length: 153
    Connection: keep-alive

    命令拆解

    部分 含义
    curl HTTP 请求工具
    192.168.226.128:8004/admin 用物理网卡 IP(非 127.0.0.1)访问 /admin 路径
    -I 只显示响应头,不下载页面内容

    失败原因:来源 IP 不是 127.0.0.1,被 deny all 拦截。


    测试 2:本地 + 正确密码 → ✅ 成功

    bash

    [root@localhost ~]# curl -u admin:123 http://127.0.0.1:8004/admin/
    site04

    命令拆解

    部分 含义
    -u admin:123 user,提供用户名 admin,密码 123
    http://127.0.0.1:8004/admin/ 用本地回环地址访问(注意末尾有 /)
    site04 返回的页面内容

    成功原因:来源 IP 是 127.0.0.1(通过 allow)+ 用户名密码正确(通过 auth_basic)。


    测试 3:本地 + 错误用户名 → 401 Unauthorized

    bash

    [root@localhost ~]# curl -I -u root:123 http://127.0.0.1:8004/admin/
    HTTP/1.1 401 Unauthorized
    WWW-Authenticate: Basic realm="Tip: input password!"

    命令拆解

    部分 含义
    -u root:123 用户名 root,密码 123
    -I 只显示响应头

    失败原因:用户名 root 不在 .htpasswd 密码文件中,认证失败。


    测试 4:本地 + 正确密码 + 模拟爬虫 → 403 Forbidden

    bash

    [root@localhost ~]# curl -I -u admin:123 -H 'User-agent: bot' http://127.0.0.1:8004/admin/
    HTTP/1.1 403 Forbidden

    命令拆解

    部分 含义
    -u admin:123 提供了正确的用户名和密码(但没用上)
    -H 'User-agent: bot' Header,自定义请求头,设置 User-Agent 为 bot
    -I 只显示响应头

    失败原因:User-Agent 包含 “bot”,被外层的 if 语句提前拦截,返回 403,认证环节未执行。


    401 vs 403 区别

    状态码 含义 触发场景
    401 Unauthorized 未认证 用户名密码错误或缺失
    403 Forbidden 禁止访问 IP被拒绝 或 User-Agent被拦截

    记忆要点:


    完整执行流程图

    text

                        用户请求
                            ↓
            ┌───────────────────────────────────┐
            │  第 1 层:检查 User-Agent         │
            │  是否包含 "bot"?                  │
            └───────────────────────────────────┘
                  ↓                    ↓
                是 (测试4)            否 (测试1、2、3)
                  ↓                    ↓
             403 Forbidden    ┌─────────────────────┐
             (爬虫拦截)       │ 第 2 层:检查 IP    │
                              │ 是否 127.0.0.1?     │
                              └─────────────────────┘
                                    ↓          ↓
                                   是          否 (测试1)
                                    ↓          ↓
                              ┌─────────────────────┐
                              │ 第 3 层:检查密码    │
                              │ 用户名密码正确?     │
                              └─────────────────────┘
                                    ↓          ↓
                                   是          否 (测试3)
                                    ↓          ↓
                             ┌─────────────────────┐
                             │ 成功返回 index.html │
                             │ (测试2 ✅)          │
                             └─────────────────────┘

    日志相关

    访问日志

    记录客户端请求信息(IP、请求方法、状态码、响应大小等)

    相关配置指令

    Syntax:    access_log path [format [buffer=size] [gzip[=level]] [flush=time] [if=condition]];
               access_log off;
    Default:   access_log logs/access.log combined;
    Context:   http, server, location, if in location, limit_except
    
    
    Syntax:    log_format name [escape=default|json|none] string ...;
    Default:   log_format combined "...";
    Context:   http

    官方案例

    # 定义日志格式
    log_format compression '$remote_addr - $remote_user [$time_local] '
                           '"$request" $status $bytes_sent '
                           '"$http_referer" "$http_user_agent" "$gzip_ratio"';
    # 定义访问日志
    access_log /spool/logs/nginx-access.log compression buffer=32k;

    错误日志

    记录服务器错误、警告及调试信息

    相关配置指令

    Syntax:    error_log file [level];
    Default:   error_log logs/error.log error;
    Context:   main, http, mail, stream, server, location
    
    # 日志级别:debug info notice warn error crit alert emerg

    案例分析:参考主配置文件中日志相关配置

    常用变量(不用记,用到了翻一下就行)

    内置变量

    常用内置变量

    $remote_addr;
    # 存放了客户端的地址,注意是客户端的公网IP
    $proxy_add_x_forwarded_for;
    # 此变量表示将客户端IP追加请求报文中X-Forwarded-For首部字段,多个IP之间用逗号分隔,如果请求中没有X-Forwarder-For,就使用$remote_addr
    $args;
    # 变量中存放了URL中的参数
    $document_root;
    # 保存了针对当前资源的系统根目录
    $document_uri;
    # 保存了当前请求中不包含参数的URI,注意是不包含请求的指令,比如/img/logo.png
    $host;
    # 存放了请求的host名称
    limit_rate 10240;
    echo $limit_rate;
    # 如果nginx服务器使用limit_rate配置了显示网络速率,则会显示,如果没有设置,则显示0
    $remote_port;
    # 客户端请求Nginx服务器时随机打开的端口,这是每个客户端自己的端口
    $remote_user;
    # 已经经过Auth Basic Module验证的用户名
    $request_body_file;
    # 做反向代理时发给后端服务器的本地资源的名称
    $request_method;
    # 请求资源的方式,GET/PUT等等
    $request_filename;
    # 当前请求的资源文件的磁盘路径,由root或alias指令与URL请求生成的文件绝对路径
    # /apps/nginx/html/www/index.html
    $request_uri;
    # 包含请求参数的原始URI,不包含主机名,相当于:$document_uri?$args
    $scheme;
    # 请求的协议,例如:http,https,ftp等等
    $server_protocol;
    # 保存了客户端请求资源使用的协议版本,例如:HTTP/1.0,HTTP/1.1,HTTP/2.0等等
    $server_addr;
    # 保存了服务器的IP地址
    $server_name;
    # 请求的服务器的主机名
    $server_port;
    # 请求的服务器的端口号
    $http_<name>
    # name为任意请求报文首部字段,表示记录请求报文的首部字段
    $http_user_agent;
    # 客户端浏览器的详细信息
    $http_cookie;
    # 客户端的cookie信息
    $cookie_<name>
    # name为任意请求报文首部字段cookie的key名

    自定义变量

    假如需要自定义变量名和值,使用指令set $variable value;

    语法格式:

    Syntax:set $varible value;
    Default: -
    Context: server, location, if

    范例:

    [root@localhost ~]# vim /apps/nginx/conf.d/www.conf
    set $name zs;
    echo $name;
    set $my_port $server_port;
    echo $my_port;
    echo "$server_name:$server_port";

    一般情况下,日志保持默认即可

    项目 默认配置 说明
    访问日志 access_log logs/access.log combined; 记录所有请求,格式为标准 combined
    错误日志 error_log logs/error.log error; 记录 error 及以上级别

    大多数场景下,默认配置已经足够使用。

    网页压缩技术

    网页压缩技术主要通过 ngx_http_gzip_module 模块实现,它能显著减少传输数据量,提升网站加载速度和用户体验

    # 启用或禁用 gzip 压缩,默认关闭
    gzip on | off;
    # 压缩比由低到高1到9,默认为1
    gzip_comp_level level;
    # 禁用 IE6 gzip 功能
    gzip_disable "MSIE [1-6].";
    # gzip 压缩的最小文件,小于设置值的文件将不会压缩
    gzip_min_length 1k;
    # 启用压缩功能时,协议的最小版本,默认 HTTP/1.1
    gzip_http_version 1.0 | 1.1;
    # 指定 Nginx 服务需要向服务器申请的缓存空间的个数和大小,平台不同,默认:32 4k或者 16 8k
    gzip_buffers number size;
    # 指明仅对哪些类型的资源执行压缩操作,默认为 gzip_types text/html,不用显示指定,否则出错
    gzip_types mime-type ...;
    # 如果启用压缩,是否在相应报文首部插入 "vary: Accept-Encoding",一般建议打开
    gzip_vary on | off

    案例分析:参考 Apache 对应案例的测试验证思路,其实压缩正常用不到,用到了再说,一样的思路,不会改变网站服务内容


    Nginx 第三方模块

    第三方模块是对Nginx的功能扩展,第三方模块需要在编译安装Nginx的时候使用参数–add-module=PATH指定路径添加,有的模块是由公司的开发人员针对业务需求定制开发的,有的模块是开源爱好者开发好之后上传到GitHub进行开源的模块,Nginx支持第三方模块需要从源码重新编译支持.

    开源 echo模块:https://github.com/openresty/echo-nginx-module

    [root@localhost nginx-1.22.0]# vim /apps/nginx/conf.d/echo.conf
    server {
        listen 80;
        server_name echo.test.com;
    
        location /main {
            index index.html;
            default_type text/html;
            echo "hello world,main-->";
            echo $remote_addr;
            echo_reset_timer;
            # 将计时器开始时间重置为当前时间
    
            echo_location /sub1;
            echo_location /sub2;
            echo "took $echo_timer_elapsed sec for total.";
    }
        location /sub1 {
            echo_sleep 2;
            echo hello;
    }
        location /sub2 {
            echo_sleep 1;
            echo world;
    }
    }
    
    
    # 重新编译nginx,以前的配置文件不会丢失
    [root@localhost ~]# cd /usr/local/src
    [root@localhost src]# wget https://github.com/openresty/echo-nginx-module/archive/refs/heads/master.zip
    [root@localhost src]# unzip echo-nginx-module-master.zip
    [root@localhost src]# mv echo-nginx-module-master echo-nginx-module
    [root@localhost src]# cd nginx-1.22.0
    [root@localhost nginx-1.22.0]# ./configure --prefix=/apps/nginx 
    --user=nginx 
    --group=nginx 
    --with-http_ssl_module 
    --with-http_v2_module 
    --with-http_realip_module 
    --with-http_stub_status_module 
    --with-http_gzip_static_module 
    --with-pcre 
    --with-stream 
    --with-stream_ssl_module 
    --with-stream_realip_module 
    --add-module=/usr/local/src/echo-nginx-module
    [root@localhost nginx-1.22.0]# make -j 2 && make install
    
    
    # 进行访问测试
    [root@localhost ~]# echo "192.168.226.128 echo.test.com" >> /etc/hosts
    [root@localhost ~]# curl echo.test.com/main
    hello world,main-->
    192.168.226.128
    hello
    world
    took 3.008 sec for total.

    实验理解

    一、什么是 Nginx 第三方模块

    Nginx 本身是一个核心程序,只提供基础的 Web 服务器功能。第三方模块是对 Nginx 的功能扩展,可以增加额外特性。

    特点 说明
    来源 公司内部开发(业务定制)或开源社区(GitHub)
    安装方式 需要在编译安装 Nginx 时通过 --add-module=PATH 指定模块源码路径
    与业务的关系 完全没关系,只是为了增强 Nginx 的功能(如调试、测试、特殊响应处理)

    二、Echo 模块简介

    Echo 模块(echo-nginx-module)是由 OpenResty 作者章亦春(agentzh)开发的开源模块。

    核心功能:在 Nginx 配置文件中,像写 Shell 脚本一样输出内容、控制流程、进行子请求等。

    常用指令速查

    指令 作用
    echo 输出字符串(类似 Shell 的 echo)
    echo_sleep 非阻塞睡眠(秒)
    echo_location 串行执行子请求(上一个完成后再执行下一个)
    echo_location_async 并行执行子请求(同时发起多个)
    echo_reset_timer 重置计时器起点
    $echo_timer_elapsed 从计时起点到现在的耗时(秒)

    三、配置文件详解

    nginx

    server {
        listen 80;
        server_name echo.test.com;
    
        location /main {
            index index.html;
            default_type text/html;
            echo "hello world,main-->";
            echo $remote_addr;
            echo_reset_timer;
    
            echo_location /sub1;
            echo_location /sub2;
    
            echo "took $echo_timer_elapsed sec for total.";
        }
    
        location /sub1 {
            echo_sleep 2;
            echo hello;
        }
    
        location /sub2 {
            echo_sleep 1;
            echo world;
        }
    }

    逐段拆解

    代码 含义
    listen 80; 监听 80 端口
    server_name echo.test.com; 域名为 echo.test.com

    /main 路径执行顺序

    nginx

    echo "hello world,main-->";        # 1. 输出第一行
    echo $remote_addr;                 # 2. 输出客户端 IP
    echo_reset_timer;                  # 3. 重置计时器(从现在开始计时)
    echo_location /sub1;               # 4. 串行执行 /sub1(等它完成后继续)
    echo_location /sub2;               # 5. 串行执行 /sub2(等它完成后继续)
    echo "took $echo_timer_elapsed sec for total.";  # 6. 输出总耗时

    关键:echo_location 是串行的,必须等 /sub1 完成后才执行 /sub2。

    /sub1 路径

    nginx

    echo_sleep 2;    # 非阻塞睡眠 2 秒
    echo hello;      # 输出 "hello"

    /sub2 路径

    nginx

    echo_sleep 1;    # 非阻塞睡眠 1 秒
    echo world;      # 输出 "world"

    四、执行时间线

    text

    时间 0s:  /main 开始
             → 输出 "hello world,main-->"
             → 输出 "192.168.226.128"
             → echo_reset_timer (计时器归零)
             → 开始执行 /sub1
    
    时间 0-2s: /sub1 睡眠 2 秒
             2s 时: 输出 "hello",/sub1 完成
    
    时间 2-3s: 开始执行 /sub2,睡眠 1 秒
             3s 时: 输出 "world",/sub2 完成
    
    时间 3s: 回到 /main,输出 "took 3.008 sec for total."

    总耗时:2 秒(sub1)+ 1 秒(sub2)= 约 3 秒

    Nginx 添加第三方模块功能,必须重新编译。


    为什么必须重新编译?

    Nginx 官方提供的二进制包(如 yum install nginx)是一个固定功能的版本,只包含官方内置模块。第三方模块(如 Echo 模块)是额外的 C 语言代码,必须和 Nginx 核心代码一起编译成可执行文件才能使用。

    流程本质:

    text

    Nginx源码 + 第三方模块源码 → 编译 → 新的nginx二进制文件

    编译时通过 --add-module=/path/to/module 把第三方模块”绑”进 Nginx 里。


    编译 vs 不编译的对比

    方式 优点 缺点
    yum/apt 安装 方便快捷,自动管理依赖 功能固定,无法添加第三方模块
    源码编译 完全可控,可添加任意模块 需要手动编译,升级麻

    其他配置项

    Alias

    alias: 定义路径别名,会把访问的路径重新定义到其指定的路径,文档映射的另一种机制,仅能用于location上下文,此指令使用较少

    案例:

    [root@localhost conf]# vim /apps/nginx/conf.d/test.conf
    server {
      listen 80;
      server_name a.test.com;
    
      location /about/ {
      # 使用alias的时候uri后面加了斜杠,下面的路径也必须加,不然403错误
        alias /apps/nginx/html/about/;
        # 当访问about的时候,会显示alias定义的/apps/nginx/html/about/里面的内容
      }
    }
    
    # 重启Nginx并访问测试
    [root@localhost ~]# systemctl reload nginx
    [root@localhost ~]# curl a.test.com/about/
    about
    即使不写 root,Nginx 默认 root 是编译时的 html 目录(通常是 /usr/local/nginx/html 或 /etc/nginx/html)

    用公式表达

    text

    【没有 alias 时】
    请求:/about/index.html
         ↓
    实际路径 = root + /about/index.html
         ↓
    例如:/var/www + /about/index.html = /var/www/about/index.html
    
    
    【有 alias 时】
    请求:/about/index.html
         ↓
    实际路径 = alias(直接把 /about/ 替换掉)
         ↓
    例如:/apps/nginx/html/about/index.html

    text

    【发起请求】
    a.test.com/about/index.html
             ↓
    【匹配 location】
    location /about/ {   ← 匹配成功!
        alias /apps/nginx/html/about/;
    }
             ↓
    【处理逻辑】
    因为匹配到了 /about/,所以 URL 中 /about/ 这个部分被 alias 定义的路径替换
             ↓
    【最终读取】
    /apps/nginx/html/about/index.html

    请求 /about/ 的时候,因为这个 location 被匹配到了,所以不用管外面的 root 是什么,直接用 alias 里写的路径去替换 URL 中的 /about/ 部分,然后去那个路径找文件。


    自定义错误页面

    定义错误页,以指定的响应状态码进行响应,可用位置: HTTP, server, location, if in location

    范例:

    [root@localhost static3]# vim /apps/nginx/conf.d/test.conf
    server {
        listen 80;
        server_name a.test.com;
        auth_basic "login password";
        auth_basic_user_file /apps/nginx/conf/.htpasswd;
        error_page 404 /40x.html;
        location = /1.jpg {
            index index.html;
            root /apps/nginx/static1;
        }
        location /40x.html{
            root /apps/nginx/html;
        }
    }
    [root@localhost html]# echo "<h1>404 not found</h1>" > /apps/nginx/html/40x.html       # 自定义错误界面内容 

    范例:

    error_page 404 /index.html;
    # 如果404,就跳转到主页

    核心原理

    error_page 的作用是:当 Nginx 遇到指定的 HTTP 错误码时,返回另一个 URI(内部重定向),而不是直接返回错误页面。


    你的配置拆解

    nginx

    server {
        listen 80;
        server_name a.test.com;
    
        error_page 404 /40x.html;          # ① 404 时跳转到 /40x.html
    
        location = /1.jpg {
            index index.html;
            root /apps/nginx/static1;      # ② 图片在这
        }
    
        location /40x.html {
            root /apps/nginx/html;         # ③ 错误页在这
        }
    }

    完整工作流程

    步骤 发生什么
    ① 用户访问 a.test.com/不存在的文件.jpg
    ② Nginx 在所有 location 中找这个文件,没找到
    ③ Nginx 触发 404 错误
    ④ 看到 error_page 404 /40x.html; → 内部重定向到 /40x.html
    ⑤ 请求 /40x.html 匹配到 location /40x.html
    ⑥ 使用 root /apps/nginx/html; → 查找 /apps/nginx/html/40x.html
    ⑦ 返回该文件内容(你写的 <h1>404 not found</h1>)给用户

    关键:内部重定向 vs 外部跳转

    text

    【error_page】
    用户请求 → 404错误 → Nginx内部重新请求 /40x.html → 返回内容
    URL 不变!用户看不到跳转
            ↓
    【外部跳转(rewrite)】
    用户请求 → Nginx返回 302 → 浏览器跳转到新URL → URL改变

    长连接配置

    [root@localhost html]# vim /apps/nginx/conf/nginx.conf
    
    keepalive_timeout timeout [header_timeout];
    # 设定保持连接超时时长,0表示禁止长连接,默认为75s,通常配置在http字段作为站点全局配置
    keepalive_requests number;
    # 在一次长连接上所允许请求的资源的最大数量,默认为100次,建议适当调大,比如:500

    范例:

    [root@localhost html]# vim /apps/nginx/conf/nginx.conf
    http {
    ...
    keepalive_requests 3;
    keepalive_timeout 65 60;
    # 开启长连接后,返回客户端的会话保持时间为60s,单次长连接累计请求达到指定次数请求或65秒就会被断开,后面的60为发送给客户端应答报文头部中显示的超时时间设置为60s,如不设置客户端将不显示超时时间。
    keep-Alive:timeout=60;
    # 浏览器收到的服务器返回的报文
    # 如果设置为keepalive_timeout 0表示关闭会话保持功能,将如下显示:
    Connection:close  # 浏览器收到的服务器返回的报文
    # 使用命令测试
    [root@localhost html]# telnet a.test.com 80
    Trying 192.168.226.128...
    Connected to a.test.com.
    Escape character is '^]'.
    GET / HTTP/1.1
    HOST: a.test.com

    image-20260819192055206

    image-20260819192707706


    作为下载服务器

    ngx_http_autoindex_module模块处理以斜杠字符”/”结尾的请求,并生成目录列表可以作为下载服务配置使用

    官方文档:https://nginx.org/en/docs/http/ngx_http_autoindex_module.html

    相关指令:

    autoindex on|off;
    # 自动文件索引功能,默认off
    autoindex_exact_size on|off;
    # 计算文件确切大小(单位bytes),off显示大概大小(单位K、M),默认on
    autoindex_localtime on|off;
    # 显示本机时间而非GMT(格林威治)时间,默认off
    autoindex_format html|xml|json|jsonp;
    # 显示索引的页面分割,默认html
    limit_rate rate;
    # 限制响应客户端传输速率(除GET和HEAD以外的所有方法),单位B/s,既bytes/second,默认值0,表示无限制,此指令由ng

    范例:实现下载站点

    [root@localhost ~]# mkdir -p /apps/nginx/html/www/download
    [root@localhost ~]# cd /apps/nginx/html/www/download
    [root@localhost download]# touch f1
    [root@localhost download]# touch f2
    [root@localhost ~]# vim /etc/nginx/conf.d/www.conf  #默认的yum安装
    server {
        listen 80;
        server_name file.test.com;
        location /download {
            autoindex on;    
            # 自动索引功能,开启才会展示出文件列表
            autoindex_exact_size off;    
            # 关闭详细文件大小统计,让文件大小显示MB,GB单位,默认为b
            autoindex_localtime on;    
            # on表示显示本机时间
            limit_rate 1024k;      
            # 限速,默认不限速
            root /apps/nginx/html/www;
        }
    }
    
    
    # 修改windwos里面的hosts
    192.168.226.128 file.test.com
    测试http://file.test.com/download/ 

    image-20260821095005960

    windows的本地hosts使用

    你用管理员身份打开,然后修改后保存到桌面,把文件拖到这个路径,==替换原本的hosts==,这样就保存了

    image-20260821095228087

    image-20260821095322300


    Nginx 状态页

    基于Nginx模块ngxhttp_stub_status module实现,在编译安装Nginx的时候需要添加编译参数–with-http_stub_status_module,否则配置完成之后监测会是提示语法错误

    注意:状态页显示的是整个服务器的状态,而非虚拟主机的状态

    [root@localhost ~]# vim /etc/nginx/conf.d/www.conf
    server {
        listen 80;
        server_name status.test.com;
    
        location /status {
            stub_status on;
            # 开启nginx状态页显示
            allow 192.168.226.0/24;
            deny all;
        }
    }
    
    [root@localhost ~]# vim /etc/hosts
    192.168.226.128 status.test.com
    [root@localhost download]# curl http://status.test.com/status
    Active connections: 1
    server accepts handled requests
     1 1 1
    Reading: 0 Writing: 1 Waiting: 0

    image-20260821110241918

    image-20260821110607828

    image-20260821110708911

    其他

    其他配置参数很多没必要记,遇到了再说,再学一下具体配置参数,不用慌,主要配置参数会就行


    HTTPS 功能

    Web网站的登录页面都是使用HTTPS加密传输的,加密数据以保障数据的安全,HTTPS能够加密信息,以免敏感信息被第三方获取,所以很多银行网站或电子邮箱等等安全级别较高的服务都会采用HTTPS协议,HTTPS其实是有两部分组成:HTTP + SSL/ TLS,也就是在HTTP上又加了一层处理加密信息的模块。服务端和客户端的信息传输都会通过TLS进行加密,所以传输的数据都是加密后的数据。

    配置参数

    Nginx的HTTPS功能基于模块ngx_http_ssl_module实现,因此如果是编译安装的Nginx要使用参数ngx_http_ssl_module开启ssI功能,但是作为Nginx的核心功能,yum安装的Nginx默认就是开启的,编译安装的Nginx需要指定编译参数–with-http_ssl_module开启

    官方文档:https://nginx.org/en/docs/http/ngx_http_ssl_module.html

    配置参数如下:

    ssl on | off;
    listen 443 ssl;
    # 为指定的虚拟主机配置是否启用ssl功能,此功能在1.15.0废弃,使用listen [ssl]替代。
    ssl_certificate /path/to/file;
    # 当前虚拟主机使用使用的公钥文件,一般是crt文件
    ssl_certificate_key /path/to/file;
    # 当前虚拟主机使用的私钥文件,一般是key文件
    ssl_protocols [SSLv2] [SSLv3] [TLSv1] [TLSv1.1] [TLSv1.2];
    # 支持ssl协议版本,早期为ssl现在是TSL,默认为后三个
    ssl_session_cache off | none | [builtin[:size]] [shared:name:size];
    # 配置ssl缓存
        off: 
        # 关闭缓存
        none: 
        # 通知客户端支持ssl session cache,但实际不支持
        builtin[:size]:
        # 使用OpenSSL内建缓存,为每worker进程私有
        [shared:name:size]:
        # 在各worker之间使用一个共享的缓存,需要定义一个缓存名称和缓存空间大小,一兆可以存储4000个会话信息,多个虚拟主机可以使用相同的缓存名称。
    ssl_session_timeout time;
    # 客户端连接可以复用ssl session cache中缓存的有效时长,默认5m

    自签名证书

    [root@localhost ~]# cd /etc/nginx
    [root@localhost nginx]# mkdir certs && cd certs
    [root@localhost certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout ca.key -x509 -days 3650 -out ca.crt
    [root@localhost certs]# openssl req -newkey rsa:4096 -nodes -sha256 -keyout iproute.cn.key -out iproute.cn.csr
    [root@localhost certs]# openssl x509 -req -days 36500 -in iproute.cn.csr -CA ca.crt -CAkey ca.key -CAcreateserial -out iproute.cn.crt
    [root@localhost certs]# cat iproute.cn.crt ca.crt > iproute.crt
    [root@localhost certs]# openssl x509 -in iproute.cn.crt -noout -text

    证书配置

    [root@localhost certs]# vim /etc/nginx/conf.d/ssl.conf
    server {
        listen 80;
        listen 443 ssl;
        ssl_certificate  /etc/nginx/certs/iproute.crt;
        ssl_certificate_key  /etc/nginx/certs/iproute.cn.key;
        ssl_session_cache  shared:sslcache:20m;
        ssl_session_timeout  10m;
        root /usr/share/nginx/html;              # yum 安装默认网站目录 /usr/share/nginx/html
    }

    实践

    image-20260821120521753


    Nginx 架构和进程

    Nginx 架构

    Nginx 采用了 master-worker 架构,由 master 进程负责通信和调度,worker 进程响应具体的请求Nginx 进程模型

    Nginx 的进程模型是其高性能和高并发的核心,采用多进程架构(默认模式),主要由 Master 进程和多个 Worker 进程组成,结合异步非阻塞 I/O 模型实现高效请求处理

    image-20260806155507239

    Master 进程:

    Worker 进程:

    工作细节

    image-Nginx进程模型工作细节01

    image-20260806155546773

    image-20260821124558347

    Nginx 进程间通信

    图示如下

    image-20260806155602509

    信号:Master 进程通过信号控制 Worker 进程的生命周期及配置更新,典型场景:SIGHUP(重新加载配置文件)、SIGTERM(优雅关闭 Worker 进程)、SIGUSR1(重新打开日志文件) 管道:Master 进程与 Worker 进程之间单向传递指令,Master 进程传递 Worker ID、指令、索引、文件描述符等等,Worker 进程监听管道事件并执行具体事项 共享内存:Worker 进程间共享数据,典型场景:限流计数、缓存状态等等

    text

                        ┌─────────────────┐
                        │   Master 进程   │  ← root 运行,管理者
                        │   PID: 12345    │
                        └────────┬────────┘
                                 │
                  ┌──────────────┼──────────────┐
                  │              │              │
                  ▼              ▼              ▼
         ┌─────────────┐ ┌─────────────┐ ┌─────────────┐
         │ Worker 1    │ │ Worker 2    │ │ Worker 3    │  ← 普通用户运行
         │ PID: 12346  │ │ PID: 12347  │ │ PID: 12348  │    处理客户端请求
         └─────────────┘ └─────────────┘ └─────────────┘
                  │              │              │
                  └──────────────┼──────────────┘
                                 ▼
                        ┌─────────────────┐
                        │   客户端请求     │
                        │   (用户访问)     │
                        └─────────────────┘

    生产环境黄金原则

    1. 永远不要 kill Master 进程,除非你知道自己在做什么
    2. 用 nginx -s reload 而不是 kill 来重载配置
    3. 用 systemctl 管理服务,而不是手动 pkill
    4. 如果非要 kill Worker,用 kill(SIGTERM)而不是 kill -9,让 Worker 优雅退出
    5. 测试环境随便玩,生产环境要谨慎

    一句话总结

    Kill Worker → Master 自动复活,基本无感 Kill Master → 服务失控,不会自动恢复,需要人工干预 Kill 全部 → 服务完全中断,需手动重启


    多进程 vs 多线程:稳定性与效率的博弈

    1. 多线程(代表:Apache Worker 模式)

    核心逻辑:一个进程里开几百个线程,每个线程处理一个请求。

    优势(效率高):

    劣势(稳定性差):

    2. 多进程(代表:Nginx)

    核心逻辑:一个进程只处理一部分请求(Master 管调度,Worker 各干各的)。

    优势(稳定性优先):

    劣势(资源消耗大):

    为什么 Nginx 敢用”更吃资源”的多进程?

    按道理说,多进程又重、通信又慢,为什么 Nginx 这么火?因为 Nginx 扬长避短了:

    1. 用资源换稳定性:现在的服务器内存动不动几十 GB,多开几个 Worker 进程(通常等于 CPU 核数)对内存来说根本不是事。用可控的内存开销,换来 99.999% 级别的服务可用性,这笔投入完全值得。
    2. 绕开锁竞争瓶颈:Nginx 让每个 Worker 进程独享自己的连接列表(epoll 队列),每个 Worker 独立监听和接收连接,基本上不需要进程间加锁。而多线程最头疼的”锁竞争”问题,在 Nginx 这里被优雅地规避了。
    3. CPU 缓存亲和性:多进程模式下,可以通过配置(worker_cpu_affinity)将每个 Worker 进程绑定到固定的 CPU 核心上,L1/L2 缓存命中率极高。多线程模式在多个核心间频繁切换上下文,反而容易导致缓存失效(Cache Miss),降低性能。

    最终结论

    在互联网高并发场景下,”稳定可用”的优先级远高于”极致省内存”。用户宁愿接受少量的性能损耗,也不能接受服务因为某个请求异常而彻底返回 502。

    Apache(多线程)追求的是压榨硬件性能的效率;而 Nginx(多进程)追求的是不因单个故障而全面崩溃的稳定性。


    性能优化

    CPU性能相关

    user    nginx nginx;    #启动Nginx工作进程的用户和组
    worker_processes [number | auto];   #启动Nginx工作进程的数量,一般设为和CPU核心数相同
    worker_cpu_affinity 0001 0010 0100 1000;  # 将Nginx工作进程绑定到指定的CPU核心,默认Nginx是不进行进程绑定的,绑定并不是意味着当前nginx进程独占一核心CPU,但是可以保障此进程不会运行在其他核心上,这就极大减少了nginx的工作进程在不同的cpu核心上的来回跳转,减少了cpu对进程的资源分配与回收以及内存管理等,因此可以有效的提升nginx服务器的性能。
    CPU MASK:0001    0号CPU
              0010    1号CPU
              0100    2号CPU
              1000    3号CPU
    [root@localhost ~]# watch -n.5 'ps axo pid,cmd,psr,nice |grep nginx'

    image-20260821165919510


    工作优先级与文件并发数

    worker_priority 0;   #工作进程优先级(-20~19)
    worker_rlimit_nofile 65536;     #所有worker进程能打开的文件数量上线,包括:Nginx的所有连接(例如与代理服务器的连接等),而不仅仅是与客户端的连接,另一个考虑因素是实际的并发连接数不能超过系统级别的最大打开文件数的限制,最好与ulimit -n的值保持一致
    [root@localhost ~]# vim /etc/security/limits.conf
    *        soft    nofile    102400
    *        hard    nofile    102400
    
    
    # 案例-修改优先级
    root@localhost nginx-1.22.0]# vim /etc/nginx/conf/nginx.conf
    worker_priority -20;
    
    #重载配置
    [root@localhost nginx-1.22.0]# nginx -t
    [root@localhost nginx-1.22.0]# systemctl restart nginx
    
    # 查看优先级
    [root@localhost ~]# watch -n.5 'ps axo pid,cmd,psr,nice |grep nginx'
    Every 0.5s: ps axo pid,cmd,psr,nice |grep nginx                   Mon Jul 15 08:11:44 2024
    
     22950 nginx: master process /apps   1   0
     22951 nginx: worker process         0 -20
     22952 nginx: worker process         1 -20
     22953 nginx: worker process         2 -20
     22954 nginx: worker process         3 -20
     23004 grep nginx                    3   0

    image-20260821171325341

    image-20260821171422465

    其他优化配置

    daemon off;    # 前台运行nginx服务,用于测试、docker等环境
    master_process off|on;    # 是否开启Nginx的master-worker工作模式,仅用于开发调试场景,默认为on
    events {
      worker_connections 65536;    # 设置单个工作进程的最大并发连接数
      use epoll;    # 使用epoll事件驱动,Nginx支持众多的事件驱动,比如:select、poll、epoll,只能设置在events模块中
      accept_mutex on;  # on为同一时刻一个请求轮流由work进程处理,而防止被同时唤醒所有worker,避免多个睡眠进程被唤醒的设置,默认为off,新请求会唤醒所有worker进程,此过程也被称为"惊群",因此nginx刚安装完以后要进行适当的优化,建议设置为on
      multi_accept on;  # on时Nginx服务器的每个工作进程可以同时接受多个新的网络连接,此指令默认为off,即默认为一个工作进程只能一次接受一个新的网络连接,打开后几个同时接受多个,建议设置为on
    }

    默认主配置文件

    image-20260821182810499

    Nginx高并发性能调优

    Events 模块性能调优详解

    你截图里的 events 块配置了四个关键参数,都是 Nginx 高并发性能调优的核心。

    events 块完整配置

    nginx

    events {
        worker_connections 65536;   # 每个 Worker 最大并发连接数
        use epoll;                  # 事件驱动模型
        accept_mutex on;            # 接受互斥锁,防止惊群
        multi_accept on;            # 多接受,一次接受多个连接
    }

    1. worker_connections

    作用:设置每个 Worker 进程能够同时打开的最大连接数(含所有连接,不只客户端)。

    计算公式:

    text

    Nginx 最大并发连接数 = worker_processes × worker_connections

    举例:

    设置建议:

    场景 推荐值
    低并发(个人博客) 1024 或 2048
    中并发(企业官网) 4096 或 8192
    高并发(互联网应用) 65536 或更大

    注意事项:

    2. use epoll

    作用:指定 Nginx 使用的事件驱动模型,用于高效管理大量并发连接。

    常见事件驱动模型对比:

    模型 适用场景 特点
    select 老旧系统、低并发 轮询检查,连接数受限(1024),效率低
    poll 老旧系统、低并发 类似 select,但无 1024 限制,效率一般
    epoll Linux 系统(推荐) 事件驱动,O(1) 复杂度,只处理活跃连接,高并发首选
    kqueue FreeBSD/macOS 系统 类似 epoll,用于 BSD 系统
    /dev/poll Solaris 系统 类似 epoll,用于 Solaris

    epoll 为什么高效?

    配置建议:

    nginx

    use epoll;   # Linux 系统直接写,Nginx 通常会自适应

    3. accept_mutex

    作用:控制多个 Worker 进程是否轮流接受新连接,防止”惊群”问题。

    什么是惊群?

    假设有 4 个 Worker 进程都在睡觉(阻塞等待新连接到来)

    新连接到达 → 内核唤醒所有 4 个 Worker → 4 个 Worker 同时抢这个新连接 → 只有 1 个抢到,其他 3 个被唤醒后啥也没干又回去睡觉

    accept_mutex 的作用:

    设置 行为
    accept_mutex on(推荐) Worker 轮流接收新连接,同一时间只有一个 Worker 被唤醒,避免惊群
    accept_mutex off 所有 Worker 同时竞争新连接,可能触发惊群,高并发下性能下降

    为什么开启?

    text

    假设瞬间有 100 个新连接同时到达
    
    multi_accept off → Worker 每次只取 1 个 → 需要重复 100 次 accept() 系统调用
    multi_accept on  → Worker 每次取多个(如 10 个)→ 只需 10 次 accept() 系统调用

    配置建议:

    nginx

    multi_accept on;   # 建议开启,提升高并发下的接受效率

    补充优化:与 worker_priority 配合

    还有一个 worker_priority -20; 参数,这是设置 Worker 进程的 nice 值:

    nginx

    worker_priority -20;   # nice 值范围 -20(最高优先级)到 19(最低优先级)

    LNMP架构

    LNMP 架构概述

    LNMP是一套技术的组合,L=Linux、N=Nginx、M=MySQL、P=PHP

    如何工作

    image-20260826122042523

    image-20260826122339397

    部署安装

    # 安装 nginx:如果编译安装可以跳过
    [root@localhost ~]# yum install nginx -y
    # 安装 php 全家桶
    [root@localhost ~]# yum install php* -y
    # 更新 php-fmp listen 配置项
    [root@localhost ~]# vim /etc/php-fpm.d/www.conf
    ......
    ;listen = /run/php-fpm/www.sock
    listen = 9000
    ......
    [root@localhost ~]# systemctl enable --now php-fpm
    # 安装 marinedb 数据库
    [root@localhost ~]# yum install -y mariadb-server mariadb
    [root@localhost ~]# systemctl enable --now mariadb
    # 设置数据库 root 用户密码
    [root@localhost ~]# mysqladmin password '123456'
    [root@localhost ~]# mysql -uroot -p123456 -e "show databases;"
    +--------------------+
    | Database           |
    +--------------------+
    | information_schema |
    | mysql              |
    | performance_schema |
    +--------------------+
    # 准备测试页面
    [root@localhost ~]# mkdir -pv /data/nginx/lnmp
    [root@localhost ~]# vim /data/nginx/lnmp/index.php
    <?php
        phpinfo();
    ?>
    
    # 测试 index.php 运行正确
    [root@localhost ~]# php /data/nginx/lnmp/index.php 
    # 添加 nginx vhost 配置文件:将 php 请求转给 php-fpm 处理
    [root@localhost ~]# vim /etc/nginx/conf.d/php.conf
    server {
        listen 80;
        server_name php.iproot.cn;
        root /data/nginx/lnmp;
    
        location / {
            index index.php index.html;
            }
        location ~ .php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
            }
    }
    
    [root@localhost ~]# nginx -s reload
    # 测试验证
    [root@localhost ~]# curl -I -H 'Hostname: php.iproute.cn' 172.16.175.129
    HTTP/1.1 200 OK
    Server: nginx/1.20.1

    相关配置

    设置 fastcgi 服务器地址

    Syntax: fastcgi_pass address;
    Default:-
    Context:location,if in location
    # 语法示例:可以指定为域名或IP地址以及端口
    fastcgi_pass location:9000;
    fastcgi_pass unix:/tmp/fastcgi.socket;

    设置 fastcgi 默认首页文件

    Syntax: fastcgi_index name;
    Default:-
    Context:http,server,location

    设置 fastcgi_param 传递变量

    Syntax: fastcgi_param parameter value [if_not_empty];
    Default:-
    Context:http,server,location
    #语法示例
    fastcgi_index index.php;
    fastcgi_param SCRIPT_FILENAME /code$fastcgi_script_name;

    实践

    image-20260826124723887

    image-20260826124751633

    image-20260826125336860

    image-20260826133331417

    1核心内容:Nginx 站点配置文件

    屏幕中央显示的是Nginx的一个虚拟主机(Server Block)配置文件内容。这个文件通常位于/etc/nginx/conf.d/目录下。

    我们来逐行解读这段配置:

    配置行 含义解析
    server { 定义一个虚拟主机配置块的开始。
    listen 80; 监听本机的80端口(即标准的HTTP网页请求端口)。
    server_name php.iproot.cn; 设置域名。当用户访问 php.iproot.cn 这个域名时,Nginx就会使用这个配置块来处理请求。
    root /data/nginx/Lnmp; 设置网站的根目录。所有静态文件(如HTML、图片)会从这个路径下寻找。
    location / { 匹配根路径/的访问规则。
    index index.php index.html; 设置默认首页文件。当用户访问目录时,会按顺序查找index.php,如果不存在则找index.html。
    location ~ .php$ { 这是一个正则匹配,专门处理所有以.php结尾的URL请求。
    fastcgi_pass 127.0.0.1:9000; 核心:将PHP脚本的解析请求转发给本机(127.0.0.1)的9000端口。这通常意味着服务器上运行着PHP-FPM服务,用来执行PHP代码。
    fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name; 告诉PHP-FPM要执行哪个PHP文件。 – $document_root 就是前面定义的 /data/nginx/Lnmp – $fastcgi_script_name 是请求的PHP文件名(比如/index.php)
    include fastcgi_params; 引入一个包含其他FastCGI相关参数(如PATH_INFO等)的标准文件,便于简化配置。

    2. 关于PHP-FPM配置

    屏幕左侧的目录树显示了 /etc/php-fpm.d/ 和其下的 www.conf。

    3. 这个架构的整体工作流程

    当你在浏览器访问 http://php.iproot.cn/index.php 时:

    1. 浏览器通过DNS解析到你的服务器IP(192.168.226.128)。
    2. Nginx接收到请求,根据 server_name 匹配到该配置块。
    3. 根据 location ~ .php$ 规则,Nginx判断这是PHP请求。
    4. Nginx通过 fastcgi_pass 将请求转交给本机的PHP-FPM(监听9000端口)。
    5. PHP-FPM执行 /data/nginx/Lnmp/index.php 文件。
    6. PHP执行后返回结果给Nginx,Nginx再返回给浏览器。

    为什么必须用 fastcgi_pass?

    因为 Nginx 本身不支持直接解析 PHP。

    Nginx 是一个 Web 服务器,它擅长:

    但它不能执行 PHP 代码。

    PHP 代码必须由 PHP-FPM(或 PHP-CGI)来执行,而 Nginx 和 PHP-FPM 之间通过 FastCGI 协议通信,fastcgi_pass 就是告诉 Nginx:”把所有 PHP 请求通过 FastCGI 协议发给这个地址”。


    对比 Apache 的差异(便于理解)

    Web 服务器 PHP 处理方式
    Apache 可以通过 mod_php 模块内置执行 PHP(不需要转发)
    Nginx 必须通过 fastcgi_pass 转发给 PHP-FPM(无法内置)

    访问

    1. curl访问

    image-20260826134145649

    1. 浏览器访问

    image-20260826134610666

    image-20260826135459300

    image-20260826135551073

    ==总结==:全部成功代表LNMP环境没问题


    数据库管理应用

    为了方便的使用数据库,我们可以安装数据库图形化管理工具 phpmyadmin

    安装部署

    # 为数据库管理工具创建虚拟主机
    [root@localhost ~]# vim /etc/nginx/conf.d/mysql.conf
    server {
        listen 80;
        server_name mysql.iproot.cn;
        root /code/phpmyadmin;
    
        location / {
            index index.php index.html;
        }
    
        location ~ .php$ {
            fastcgi_pass 127.0.0.1:9000;
            fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }
    [root@localhost ~]# nginx -t
    # 下载phpmyadmin源码
    [root@localhost ~]# cd /code/
    [root@localhost code]# wget https://files.phpmyadmin.net/phpMyAdmin/5.1.1/phpMyAdmin-5.1.1-all-languages.zip
    # 解压软件包,并且重命名
    [root@localhost phpmyadmin]# unzip phpMyAdmin-5.1.1-all-languages.zip
    [root@localhost phpmyadmin]# mv phpMyAdmin-5.1.1-all-languages phpmyadmin
    # 添加session文件夹权限
    [root@localhost phpmyadmin]# chown -R 777 /var/lib/php/session

    image-20260826142356321

    1. 你登录 phpMyAdmin

    text

    输入账号密码 → MySQL 验证通过
        ↓
    PHP 创建 Session 文件:sess_abc123
    内容:
      user_id = 1
      username = admin
      is_logged_in = 1
      login_time = 2026-08-26 11:00:00
        ↓
    返回浏览器:Cookie 里存了 Session ID = abc123

    2.Session 的核心机制

    text

    【第一次访问】
    用户浏览器 ──→ Nginx ──→ PHP
                              ↓
                        创建 Session 文件
                        /var/lib/php/session/sess_随机字符串
                              ↓
                        返回 Set-Cookie: PHPSESSID=随机字符串
    用户浏览器 ←──────────────────┘
        ↓
    浏览器保存 Cookie
    
    【第二次访问】
    用户浏览器(带着 Cookie: PHPSESSID=随机字符串)──→ Nginx ──→ PHP
                                                                  ↓
                                                         找到对应的 Session 文件
                                                         读取里面的数据
                                                                  ↓
                                                         "哦,你是 admin"

    Session 的本质就是:服务端的一个文件(或数据库记录),用来存储特定用户的临时数据。

    image-20260826160633952

    image-20260826160927261

    image-20260826160936936

    image-20260826161039242


    博客系统

    部署虚拟主机

    # 为博客创建虚拟主机
    [root@localhost ~]# vim /etc/nginx/conf.d/typecho.conf
    server {
        listen 80;
        server_name blog.iproot.cn;
        root /code/typecho;
        index index.php index.html;
    
        location ~ .*.php(/.*)*$ {
            fastcgi_pass   127.0.0.1:9000;
            fastcgi_index  index.php;
            fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
            include fastcgi_params;
        }
    }
    
    # 检查nginx配置文件,并且重启
    [root@localhost ~]# nginx -t
    [root@localhost ~]# systemctl restart nginx
    
    # 创建typecho目录
    [root@localhost ~]# mkdir /code/typecho
    [root@localhost ~]# cd /code/typecho
    
    [root@localhost ~]# wget https://github.com/typecho/typecho/releases/latest/download/typecho.zip
    
    # 解压源码
    [root@localhost ~]# unzip typecho.zip

    image-20260826161503298

    image-20260826162039442

    创建数据库

    点击数据库,输入数据库名之后,就可以点击创建

    image-20260826162943501

    安装博客系统

    下面就可以开始进入网站安装的部分了,访问博客系统页面

    image-20260826162539262

    赋予网站根目录下usr/uploads目录权限

    [root@localhost typecho]# chmod a+w usr/uploads/

    image-20260826163028750

    在安装的pwd下 touch config.inc.php文件

    image-20260826163255979

    image-20260826163501610

    image-20260826163607130

    网盘服务

    部署虚拟主机

    # 为网盘创建虚拟主机
    [root@localhost themes]# vim /etc/nginx/conf.d/kod.conf
    server {
            listen 80;
            server_name kod.iproot.cn;
            root /code/kod;
            index index.php index.html;
    
            location ~ .*.php(/.*)*$ {
                    root /code/kod;
                    fastcgi_pass   127.0.0.1:9000;
                    fastcgi_index  index.php;
                    fastcgi_param  SCRIPT_FILENAME $document_root$fastcgi_script_name;
                    include fastcgi_params;
            }
    }
    
    # 检查nginx配置文件,并且重启
    [root@localhost ~]# nginx -t
    [root@localhost ~]# systemctl restart nginx
    
    # 下载源代码然后解压重命名
    [root@localhost ~]# mkdir /code/kod
    [root@localhost ~]# cd /code/kod
    [root@localhost kod]# wget https://static.kodcloud.com/update/download/kodbox.1.23.zip
    
    # 解压源码
    [root@localhost kod]# unzip kodbox.1.23.zip

    image-20260826164413962

    创建数据库

    image-20260826164856680

    安装网盘系统

    浏览器访问此站点,我们发现目录权限,这个比较重要

    image-20260826165309423

    # 设置权限
    [root@localhost kod]# chown -R 777 /code/kod

    image-20260826165952286

    image-20260826170157993

    可道云网盘系统

    image-20260826170527027

  • Linux的ssh服务与ftp文件服务器

    一、核心概念

    • 非对称加密:使用一对密钥(公钥 + 私钥)。
    • 公钥(Public Key):可公开,用于加密数据。
    • 私钥(Private Key):必须保密,用于解密数据。

    二、工作原理(类比邮箱)

    • 公钥就像公开的锁:任何人都可以用它把信息”锁”进邮箱(加密)。
    • 私钥就像唯一的钥匙:只有你才能打开邮箱(解密)。
    • 即使别人知道公钥,也无法推算出私钥(数学上不可行)。

    三、SSH 密钥登录流程

    1. 生成密钥对(如截图中的 ssh-keygen -t ed25519)。
    2. 将公钥上传到远程服务器(保存在 ~/.ssh/authorized_keys)。
    3. 登录时:

    四、与你截图对应的操作

    • 你已成功生成 ed25519 密钥对:
      • 私钥:C:Usersli/.ssh/id_ed25519
      • 公钥:C:Usersli/.ssh/id_ed25519.pub
  • image-20260801194300733image-20260801194321746

    image-20260801194602372

    ==注意==:加密知道流程

    在阿里云里绑定公私钥进行登录

    image-20260801202517277

    image-20260801202540166

    总结:==禁止密码登录,全程密钥认证,每人独立密钥,操作全程可追溯。 这是大厂生产环境的铁律。==


    Ftp和NFS和Samba文件服务器与==阿里云oss(对象存储)对比==:

    一:

    1. NFS:基于网段/IP做权限控制。适合同一项目组、同一网段的多台Linux服务器共享数据(例如A机处理完数据存进去,B机直接读走)。只要IP在允许范围内,所有机器权限一致,不讲用户差异。
    2. Samba:基于用户名做权限控制。适合同一局域网内,不同用户(如财务、人事、研发)各自登录后看到不同的共享目录,权限互不相同。同在一个局域网,但认人不认IP。
    3. OSS:基于HTTP协议,天然可跨互联网访问。适合外网用户直接通过链接下载或查看文件,无需VPN、无需挂载磁盘、无需局域网环境。

    三者本质定位

    服务 访问范围 认证依据 一句话定位
    NFS 局域网(同一网段) 客户端IP 同一网段的多台Linux服务器共享数据
    Samba 局域网(可跨网段,但通常在内网) 用户名/密码 同一局域网内,不同用户不同权限
    OSS 外网/互联网 签名链接/密钥 外网用户直接下载,无需内网环境

    最终一句话总结

    ==总结==:同一网段的 Linux 服务器之间,通过 NFS 共享同一个目录,像访问本地硬盘一样访问远程数据,省去反复拷贝的麻烦

  • Linux对象存储

  • Linux防火墙

    iptables

    -t 指定表

    -A 指定链

    -j 指定规则

    -s(–source)指定源ip

    -d(–destination)目标ip

    –dport 目标端口

    -p 指定协议

    -R INPUT 1 可替换INPUT表中第一条规则为新规则

    iptables -F 全部删除

    iptables -vnL –line-number 展示规则

    iptables -vnL INPUT –line-number 具体的链条,-t可以指定表

    删除规则

    iptables -D INPUT 1   # 建议使用对应链上的序号删除

    ==注意==:规则就删除和增加,更改:就先删除原规则,再增加

    自定义链

    dnf -y install iptables-services # 使用iptables-services自动管理
    systemctl start iptables.service
    systemctl enable iptables.service
    
    iptables -F  #清楚所有规则
    service iptables save # 保存一下
    
    
    iptables -t filter -N WEB_CHAIN  # 创建自定义链
    iptables -t filter -A INPUT  -s 192.168.18.1 -j WEB_CHAIN   # 自定义链规则,绑定至filter表中的INPUT链
    iptables -t filter -A WEB_CHAIN -p tcp -m multiport --dports 80,443 -j ACCEPT  # 自定义链规则为允许80,443端口  
    iptables -t filter -A INPUT -p tcp  -m multiport --dports 80,443 -j DROP  # 拒绝所有80,443端口
    iptables -L
    curl 127.0.0.1  # 无法访问
    # 浏览器访问192.168.18.129,可以访问
    # 链的规则从1开始逐个匹配
    
    [root@192 ~]# iptables -vnL --line-numbers
    Chain INPUT (policy ACCEPT 2608 packets, 130K bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    1     2372  118K WEB_CHAIN  all  --  *      *       192.168.18.1         0.0.0.0/0
    2        3   180 DROP       tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 80,443
    
    Chain FORWARD (policy ACCEPT 0 packets, 0 bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    
    Chain OUTPUT (policy ACCEPT 10120 packets, 1015K bytes)
    num   pkts bytes target     prot opt in     out     source               destination
    
    Chain WEB_CHAIN (1 references)
    num   pkts bytes target     prot opt in     out     source               destination
    1       18  2455 ACCEPT     tcp  --  *      *       0.0.0.0/0            0.0.0.0/0            multiport dports 80,443

    image-20260729201350618

    iptables模块实验

    ​ 1. string模块

    # 注意是output和sport
    iptables -A OUTPUT -p tcp --sport 80 -m string --algo bm --string "world" -j REJECT
    

    ​ 2. ssh实验尽量使用xshell,mobaxterm中的文件管理也会占用ssh通道

    ​ 3. limit-burst和limit,这里背景是一个令牌桶算法深入理解令牌桶算法:实现分布式系统高效限流的秘籍 在高并发系统中,“限流” 是保障服务稳定的核心手段 —— 当请求量超 – 掘金

    ​ 4. tcp flag了解即可,一般是方式tcp异常包的

    iptables -A INPUT -p tcp --tcp-flags SYN,FIN,ACK SYN
    掩码:SYN, FIN, ACK(只检查这 3 个位,其他位无视)
    目标:SYN(要求 SYN=1,FIN=0,ACK=0)
    匹配结果:匹配 TCP 握手的第一步(纯 SYN 包),这是建立新连接的标准包。
    
    iptables -A FORWARD -p tcp --tcp-flags ALL SYN,ACK
    掩码:ALL(这是 SYN,ACK,FIN,RST,URG,PSH 的简写,检查所有标志位)
    目标:SYN,ACK(要求 SYN=1,ACK=1,其他所有位必须为 0)
    匹配结果:匹配 TCP 握手的第二步(SYN-ACK 包),即服务器响应客户端的包。

    ==高并发请求场景(令牌桶+iptables)==

    令牌桶的“保护机制”拆解

    1. 核心逻辑:控制“进入内核协议栈”的包速率

    text

    外部请求 ──→ 网卡 ──→ iptables (limit匹配) ──→ 允许进入协议栈 ──→ 应用服务
                             │
                             ▼ (无令牌)
                          直接 DROP(拒绝)
    • 关键点:拒绝发生在内核层,不经过用户态应用(如 Nginx/Java 进程)。
    • 好处:即使拒绝,也几乎不消耗 CPU/内存,避免了应用层处理带来的资源开销。

    2. 令牌桶参数如何应对突发流量

    参数含义高并发下的作用
    --limit-burst初始令牌数(桶容量)允许短时突发流量通过,避免正常业务波动被误杀
    --limit令牌补充速率长期平均速率的上限,保证整体负载可控

    举例:

    bash

    iptables -A INPUT -p tcp --dport 80 -m limit --limit 100/minute --limit-burst 200 -j ACCEPT
    iptables -A INPUT -p tcp --dport 80 -j DROP
    • 瞬间来了 500 个并发请求:
      • 前 200 个有令牌 → 通过
      • 剩下 300 个 → 直接 DROP(不经过 Nginx)
    • 之后按 100 个/分钟(约 1.67 个/秒)补充令牌
    • 如果持续高压,长期速率被锁死在 ~1.67 req/s,服务器负载稳定

    ==总结==:

    令牌桶 + iptables 是在网络层给服务器戴上一个“泄压阀”——超过阈值直接在内核丢弃,不让压力传导到应用层,从而保证服务在过载时仍能部分可用,而不是完全僵死。


    iptables日常管理从rocky9.0开始推荐使用firewalld

    启用 iptables 防火墙 – 文档 – Rocky Linux 文档

    iptables snat实验

    机器初始状态(如果你的机器ip和我的有区别,按照nat网卡和桥接网卡查询结果一起更改即可)

    # server1
    nat: 192.168.18.129/24 #使用dhcp分配的或者自行配置的ip地址都可以,确保可以上网
    host-only: 192.168.199.128/24 
    
    # server2
    host-only: 192.168.199.129/24 # 默认无法上网,但是与server仅主机网卡处于一个子网

    需要配置项目

    # server1
    1.开启 Linux 内核路由转发
    默认情况下,Linux 收到不是发给自己的数据包会直接丢弃。我们需要允许它转发数据
    sysctl -w net.ipv4.ip_forward=1   # 开启转发,立即且临时生效
    echo "net.ipv4.ip_forward = 1" > /etc/sysctl.d/99-ipforward.conf  # 写入配置文件永久生效,此/etc/sysctl.conf文件是根配置,依然使用子配置文件的方式
    sysctl -p # 立即加载配置文件中参数
    
    iptables -F -t nat 
    iptables -t nat -A POSTROUTING -s 192.168.199.0/24 -o ens160 -j MASQUERADE  # 网卡是可上网的网卡
    # iptables -t nat -A POSTROUTING -s 192.168.199.0/24 -o ens160 -j SNAT --to-source 192.168.18.129
    # server2
    vi /etc/NetworkManager/system-connections/ens160.nmconnection
    [ipv4]
    method=manual
    address1=192.168.199.129/24,192.168.199.128   # ip地址不变,网关更改为server1的ip地址
    dns=114.114.114.114  # dns正常添加,否则无人能提供域名解析

    配置完成后,按以下顺序在 Server2 上进行检查,很容易排查出卡在哪一步:

    ​ 1. 测试内网连通性: ping 192.168.199.128 (确保能连上 Server1)

    ​ 2. 测试跨网段连通性: ping 192.168.18.129 (确保能连上 Server1 的外网网卡,如果这一步通了,说明 Server1 的 ip_forward 转发成功了)

    ​ 3. 测试外网 IP 连通性: ping 114.114.114.114 (如果这一步通了,说明 iptables NAT 规则成功生效)

    ​ 4. 测试域名解析: ping www.baidu.com (如果这一步通了,说明 DNS 配置正确,实验完全成功)

    两条核心命令解析

    iptables -t nat -A POSTROUTING -s 192.168.199.0/24 -o ens160 -j MASQUERADE
    1. -t nat (去哪张表?)

    指定我们要操作的是 nat 表,即修改数据包的源 IP 或目的 IP。

    1. -A POSTROUTING

    A 代表 Append,POSTROUTING是nat表里的一个链,字面意思是“路由之后”

    告诉内核,当数据包已经决定了要从哪块网卡送出去、即将离开Server1这一瞬间,把它拦下来执行后面的操作

    1. -s 192.168.199.0/24

    只有来自192.168.199.0/24这个仅主机局域网段的数据包,才会触发这条规则

    1. -o ens33

    限定只有当数据包打算从 ens33 发送出去时,规则才生效。

    1. -j MASQUERADE

    j 代表 Jump(跳转动作)。MASQUERADE 的字面意思是“伪装”,它会对符合上述所有条件的数据包做动态源地址转换(Dynamic SNAT)

    iptables -t nat -A POSTROUTING -s 192.168.199.0/24 -o ens160 -j SNAT --to-source 192.168.18.129

    当检查到从 ens160 网卡出去、且源自内网 192.168.199.0/24 的数据包时,强行将其源 IP 地址(Source IP)重写为固定的 192.168.18.129

    抓包分析观察nat过程

    server1上开启tcpdump抓包

    # 没有tcpdump,就dnf install tcpdump
    # -nn 第一个n:不解析ip地址为域名,第二个n:不解析端口号为协议
    [root@server1 ~]#  tcpdump -i any -nn host www.baidu.com
    tcpdump: data link type LINUX_SLL2
    dropped privs to tcpdump
    tcpdump: verbose output suppressed, use -v[v]... for full protocol decode
    listening on any, link-type LINUX_SLL2 (Linux cooked v2), snapshot length 262144 bytes
    23:53:46.110400 ens224 In  IP 192.168.199.129 > 180.101.49.44: ICMP echo request, id 12, seq 1, length 64
    23:53:46.110423 ens160 Out IP 192.168.18.129 > 180.101.49.44: ICMP echo request, id 12, seq 1, length 64
    23:53:46.121616 ens160 In  IP 180.101.49.44 > 192.168.18.129: ICMP echo reply, id 12, seq 1, length 64
    23:53:46.121634 ens224 Out IP 180.101.49.44 > 192.168.199.129: ICMP echo reply, id 12, seq 1, length 64

    server2上ping 百度一下,你就知道

    iptables dnat实验

    web server转发(端口转发)

    在server2上启动一个http server,期望通过server1的nat网卡访问到

    dnf install -y httpd
    systemctl start httpd
    # 宿主机浏览器访问192.168.199.129:80,可以看到网站
    # 我们期望通过访问server1 192.168.18.129:8080 可以访问的的上述网站
    iptables -t nat -A PREROUTING -d 192.168.18.129 -p tcp --dport 8080 -j DNAT --to-destination 192.168.199.129:80

    -t nat:依然是在 nat 表中做配置

    -A PREROUTING:在数据包刚进入 Server1、还没决定去哪里之前,把它拦下。因为如果等路由决定做完了,Server1 就会觉得“这是发给我 8080 的包,我自己又没开这个端口”,从而直接拒绝连接。

    -d 192.168.18.129 -p tcp –dport 8080:只有当访问的“目的地 IP”是 Server1 外网卡,且协议是 TCP,且“目标端口”是 8080 时,才触发规则。

    -j DNAT –to-destination 192.168.199.129:80:强行把这个数据包的“目的地”改成内网机 Server2 的 IP 和 80 端口。

    ssh本地端口

    可以使用192.168.18.129:3322 通过ssh连接至server2

    # server1
    iptables -t nat -A PREROUTING -d 192.168.18.129 -p tcp --dport 3322 -j DNAT --to-destination 192.168.199.129:22
    

    ssh本地转发

    将本机目的6666端口流量在路由前直接转发至22端口

    # server1
    iptables -t nat -A PREROUTING -p tcp --dport 6666 -j REDIRECT --to-port 22

    可以使用192.168.18.129:6666连接至server1自己

    firewalld核心命令

    firewall-cmd --list-all --zone=public --permanent # 查看永久生效的
    firewall-cmd --list-all --zone=public             # 查看所有public规则
    
    firewall-cmd --zone=public --add-service=http  # 临时放行
    firewall-cmd --zone=public --add-port=80/tcp   # 用端口放行
    # 注意:永久生效仅重启后才能生效,如果想要永久配置立即生效需要reload
    firewall-cmd --zone=public --add-port=80/tcp  --permanent # 永久生效
    # firewall-cmd --reload
    
    firewall-cmd --zone=public --remove-service=http
    firewall-cmd --zone=public --remove-service=http --permanent # 永久删除
    
    # 富规则,此处注意ip地址换成你自己的
    firewall-cmd --permanent --add-rich-rule='rule family="ipv4" source address="192.168.18.1" port port="80" protocol="tcp" drop'

    image-20260728192651597

    image-20260728193150862

    image-20260728193213105

    ==firewalld==

    1. Firewalld 放行策略的两种思路

    • 方法一(服务名):基于预定义的服务协议(如 http)放行。它实际是端口和协议的“别名映射”,适合通用场景,但存在命名歧义风险(例如 http 默认对应 80/tcp,若不熟悉映射关系容易混淆)。
    • 方法二(端口+协议):直接指定具体端口和传输层协议(如 80/tcp)。这种方式的优势是精确、无歧义,无需依赖服务名数据库,排障时一目了然,符合精细控制的需求。

    2. 区域(Zone)的默认逻辑

    • public 是 Firewalld 的默认区域。若不特意切换,所有网卡接口默认归属该区域,策略只管这一处即可,无需被其他区域概念干扰。
    • 临时规则(无 --permanent)立即生效但重启丢失;永久规则(加 --permanent)需重载配置,注意两者的生效时机差异。

    3. 验证与排查的工具链逻辑

    • ss:查看服务端口的监听状态(LISTEN)及进程关联,确认 Python/HTTP 服务已正确绑定 0.0.0.0:端口。
    • curl:充当测试客户端,发起 HTTP 请求报文。通过 curl -I 仅查看响应头即可快速验证放行是否生效,无需依赖浏览器。
    • 抓包工具(tcpdump / Wireshark):分别工作在 Linux 命令行和 Windows 图形界面,本质相同——提供数据包层面的证据链,可确认请求是否真正到达网卡、防火墙是否丢弃、代理是否转发。

    4. “不用名字”的设计原则

    • 防火墙策略精确到传输层(端口+TCP/UDP),而不依赖应用层别名(如 http),可以避免因服务名定义变化或误读带来的配置偏差。
    • 这与网络排查的思路一致:分层解耦——防火墙只负责网络层的门禁开关,不关心门内跑的具体是什么应用;应用层问题(如 403、500)交给 curl 返回内容和应用日志去判断。

    ==总结==:防火墙firewalld

    1. Firewalld 永久生效与立即生效的逻辑

    • 运行时(Runtime):修改立即生效,但重启丢失。
    • 永久(Permanent):修改写入配置文件,但不会自动作用于当前运行状态。
    • 完整操作:必须执行 “永久修改 + 重载(Reload)” 组合。重载的作用是用永久配置覆盖当前运行时配置,使两者同步,从而达到既永久又立即生效。注意:--reload 会中断长连接,而 --complete-reload 更彻底。

    2. 浏览器缓存 vs. curl 的测试差异

    • 浏览器(强缓存):默认遵循 HTTP 缓存协议(如 Cache-Control),命中强缓存时直接读取磁盘/内存文件,不向服务器发起网络请求。此时若用浏览器测试防火墙放行是否生效,会被缓存干扰,误以为服务异常或正常。
    • curl:每次都完整发起 TCP 连接和 HTTP 请求,默认不缓存任何资源,完全走网络链路。因此,验证防火墙策略、端口连通性、服务可用性时,curl 是更纯粹、更可信的测试工具,能绕过客户端缓存层的干扰。

    3. 端口转发(Port Forwarding)的本质

    • 这是 DNAT(目标地址转换) 或 重定向(Redirection) 行为。操作对象是进入网卡的数据包。
    • 关键点:转发规则工作在防火墙的 nat 表(或 filter 表的 FORWARD 链配合),不依赖目标端口是否有程序在监听。它是在数据包到达本地协议栈之前,将目标端口(如 8080)修改为另一个端口(如 80),修改后再交由协议栈处理。因此,只要最终转到的那个端口上有程序监听,流量就能被正常接收。

    4. 防火墙 IP 限制的局域网与外网差异

    • 局域网(同网段):设备基于 ARP 广播直接二层通信,防火墙可以依据源 IP 轻松实施访问控制(如禁止 192.168.1.x 访问)。
    • 外网(跨网段/公网):外网请求经过 NAT(网络地址转换)进入内网时,防火墙看到的是转换后的公网源 IP,或仅能看到网关接口。若想限制外网特定 IP,需在网关的外网接口入向做策略;若限制内网特定主机对外访问,需在 FORWARD 链或 OUTPUT 链做策略。本质上防火墙依然基于五元组过滤,只是外网流量通常绕过了直接的内网 IP 寻址,需配合路由和 NAT 一起分析。

    5. Netfilter 五链四表

    • 内核数据包经历的核心钩子点为 五链:PREROUTING → INPUT → FORWARD → OUTPUT → POSTROUTING。
    • 数据流向:
      • 发往本机:PREROUTING(处理目标地址转换)→ INPUT(过滤进站)→ 本地进程。
      • 经本机转发(作为路由器):PREROUTING → FORWARD(过滤转发)→ POSTROUTING(处理源地址转换)。
      • 本机发出:OUTPUT(过滤出站)→ POSTROUTING。
    • 你说的“基本都在 filter”:是对的。filter 表挂载在 INPUT、FORWARD、OUTPUT 链上,用于允许/拒绝数据包(准入控制)。而 nat 表挂在 PREROUTING、POSTROUTING、OUTPUT 上,用于修改地址/端口。常规的”端口放行”操作在 filter 表的 INPUT 链;”端口转发”操作在 nat 表的 PREROUTING 链。

    6. Firewalld 与 iptables 的冲突本质

    • 两者操作的是同一个内核 Netfilter 框架,但管理方式冲突:
      • Firewalld 是动态守护进程,维护自己的规则集快照,重启或 --reload 时会完全覆盖内核中的规则。
      • Iptables 命令直接读写内核当前规则集,是底层瞬时操作。
    • 冲突后果:手动用 iptables 添加的规则,不会被 firewalld 记录。一旦执行 firewall-cmd --reload,firewalld 会根据其配置文件重新生成规则,直接冲掉之前手动用 iptables 添加的所有规则。
    • 原则:生产环境只选其一。若用 firewalld,所有策略必须通过 firewall-cmd 管理;若必须引入 iptables 脚本,需通过 firewalld 的 --direct 或 --passthrough 接口注入,避免配置被冲刷。

    image-20260728202717222

    Firewalld实践

    image-20260729205433466

    image-20260729205444912

    ==注意==:启用一个服务器,下面添加防火墙

    image-20260729211045891

    image-20260729211241079


    ==解禁==

    image-20260729211601745

    image-20260729211611460


    云平台的防火墙

    阿里云安全组,腾讯云安全组等


    实践

      从这段终端日志来看,你(或某个操作者)在一台 Rocky Linux 服务器上完成了一次典型的 Web 环境部署与安全测试,具体步骤如下:
    1. 安装 Nginx Web 服务器
      通过包管理器安装了nginx 及其依赖(nginx-core、nginx-filesystem)。

    同时还安装了 rocky-logs-httpd(可能是日志相关包)和 cmatrix(一个终端字符动画小游戏,与业务无关,可能顺手装的)。

    1. 启动并验证 Nginx 启动Nginx服务,并查看状态,确认 运行正常(Active: active (running)),配置文件语法检查也通过了。

    2. 添加防火墙规则(阻断 Web 访问) 执行了一条 iptables 命令: iptables -A INPUT -p TCP --dport 80 -j DROP 意思是 在 INPUT 链添加规则,丢弃所有目标端口为 80 的 TCP 请求。

    3. 查看当前防火墙规则 用 iptables -vnl --line-numbers列出所有规则,确认刚才添加的 DROP规则已生效(显示在 Chain INPUT 的第一条)。

    image-20260728133815591

    image-20260728135020019

    这条命令在INPUT 链 上添加了一条规则:丢弃所有目标端口为 80 的 TCP 数据包。

    ==注意==:默认添加的规则都在filter表里面

    image-20260728135509259


    定时任务

    系统定时任务相关配置说明

    配置文件/目录路径适合场景核心格式与要求触发机制与 Rocky 9 特有行为
    /etc/cron.d/高频、精准定时的任务。(如:每 5 分钟同步一次数据,或每天凌晨 2:00 精准备份)任意命名的文件。格式必须包含“运行用户”:/5 * root /usr/bin/script独立 Crontab 格式,由 crond 守护进程直接管理,时间高度精准。
    /etc/crontab系统自带的全局配置。不建议日常运维直接修改它。格式与 /etc/cron.d/ 完全一致,同样必须指定用户独立 Crontab 格式,属于历史保留的全局总入口,建议保持原样。
    /etc/cron.hourly/需要每小时执行一次的普通脚本。纯可执行脚本按时执行,每小时的第 1 分钟左右,由 crond 强制触发执行。
    /etc/cron.daily/每天跑一次,但对具体几点几分没有严格要求的任务(如清理临时文件)。纯可执行脚本Anacron 异步触发,默认在凌晨 03:00 – 22:00 之间随机时间执行。如果服务器半夜关机,开机后会自动补跑。
    /etc/cron.weekly/每周跑一次的任务(如每周一次的大型日志轮转)。纯可执行脚本Anacron 异步触发,由 Anacron 自动控制在每周的某一天随机延迟执行。
    /etc/cron.monthly/每月跑一次的任务(如每月度的数据对账、审计统计)。纯可执行脚本Anacron 异步触发,由 Anacron 自动控制在每月的某一天的随机延迟执行。

    系统定时任务调用过程

    [系统运行] 
       ↓
    1. crond 守护进程每分钟扫描一次配置
       ↓
    2. 每小时的第 1 分钟,crond 触发执行 `/etc/cron.d/0hourly`
       ↓
    3. 0hourly 调用 `run-parts /etc/cron.hourly` 目录
       ↓
    4. 该目录下有一个核心脚本叫 `0anacron`,它被执行了
       ↓
    5. `0anacron` 唤醒了 `anacron` 进程
       ↓
    6. anacron 检查上次执行时间,开始异步调度 `/etc/cron.daily/weekly/monthly` 目录中的脚本

    为什么 Rocky Linux 9 要这么设计?

    因为传统的 cron 很死板,如果任务定在凌晨 3 点,而当时服务器断电关机了,cron 开机后绝对不会补跑。 所以,RHEL 9 / Rocky 9 的策略是:用 cron 来保证每小时雷打不动地唤醒 anacron;再让 anacron 去负责天/周/月级别的任务。anacron 会记录上一次成功的执行时间,发现错过了就会在开机后自动补跑。

    配置详解

    [root@localhost cron.hourly]# cat /etc/cron.d/0hourly
    # Run the hourly jobs
    SHELL=/bin/bash
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    01 * * * * root run-parts /etc/cron.hourly  #每小时的第 1 分钟,以 root 身份去把 /etc/cron.hourly/ 目录里的脚本全跑一遍。
    [root@localhost cron.hourly]# cat /etc/cron.hourly/0anacron
    #!/usr/bin/sh
    # Check whether 0anacron was run today already
    if test -r /var/spool/anacron/cron.daily; then
        day=`cat /var/spool/anacron/cron.daily`
    fi
    if [ `date +%Y%m%d` = "$day" ]; then
        exit 0
    fi
    
    # Do not run jobs when on battery power
    online=1
    for psupply in /sys/class/power_supply/* ; do
        if [ `cat "$psupply/type" 2>/dev/null`x = Mainsx ] && [ -f "$psupply/online" ]; then
            if [ `cat "$psupply/online" 2>/dev/null`x = 1x ]; then
                online=1
                break
            else
                online=0
            fi
        fi
    done
    if [ $online = 0 ]; then
        exit 0
    fi
    /usr/sbin/anacron -s  #这里的 -s 它代表串行化执行)告诉 anacron 严格按照 /etc/anacrontab 里规定的延迟时间,排好队一个接一个地去跑 daily、weekly、monthly 里的任务,不要同时爆发,防止瞬间消耗尽服务器的 CPU 和 IO 资源

    anacron的配置文件

    [root@localhost cron.hourly]# cat /etc/anacrontab
    # /etc/anacrontab: configuration file for anacron
    
    # See anacron(8) and anacrontab(5) for details.
    
    SHELL=/bin/sh
    PATH=/sbin:/bin:/usr/sbin:/usr/bin
    MAILTO=root
    # the maximal random delay added to the base delay of the jobs
    RANDOM_DELAY=45# 为了防止多台服务器或者多个大型任务在同一秒钟同时爆发,把 CPU 和磁盘 I/O 瞬间吃满,anacron 在启动任务前会随机生成一个 0 到 45 之间的分钟数,作为额外的等待时间
    
    # the jobs will be started during the following hours only
    START_HOURS_RANGE=3-22  # 允许任务启动的时间窗口(凌晨3点-晚上22点)
    
    #周期(天数)        基础延迟(分钟)       任务标识符         具体执行的命令
    #period in days   delay in minutes   job-identifier   command
    
    # 每天当 anacron 被唤醒时,先等待 5 分钟加上一段随机时间,然后以较低的 CPU 优先级自动执行 /etc/cron.daily 目录下的所有无后缀脚本
    1       5       cron.daily              nice run-parts /etc/cron.daily 
    # 每隔 7 天当 anacron 被唤醒时,先等待 25 分钟加上一段随机时间,然后以较低的 CPU 优先级自动执行 /etc/cron.weekly 目录下的所有无后缀脚本
    7       25      cron.weekly             nice run-parts /etc/cron.weekly
    # 每月当 anacron 被唤醒时,先等待 45 分钟加上一段随机时间,然后以较低的 CPU 优先级自动执行 /etc/cron.monthly 目录下的所有无后缀脚本
    @monthly 45     cron.monthly            nice run-parts /etc/cron.monthly
    

    现在全局看下cron任务调度的特点

    1. 针对“脚本目录”,它确实只是个“传话筒”

    对于 /etc/cron.daily/、weekly/、monthly/,crond 唯一的贡献就是在每小时的第 1 分钟通过 0hourly 去唤醒 0anacron 脚本。一旦把 anacron 唤醒了,crond 就收工了。接下来的时间计算、漏跑补回、降低优先级(nice)执行,全由 anacron 独立完成。

    2. 但对于“精准定时”,**亲自每分钟刷新**

    虽然它把天/周/月的脚本目录外包给了 anacron,但crond自己依然在以 “每分钟扫描一次” 的频率盯着以下几个地方:

    /etc/crontab(系统全局总入口文件)

    /etc/cron.d/ 目录(你存放自定义精准任务的地方,比如你自己建的 my-sync 文件)

    /var/spool/cron/ 目录(所有普通用户通过 crontab -e 提交的任务)

    平时想使用系统定时任务的特性可写入的文件

    ​ 1. /etc/cron.d/ 由crond调用

    ​ 2. /etc/cron.daily/ 由crond调用

    ​ 3. /etc/cron.weekly/ 由于anacron调用,有补跑能力

    ​ 4. /etc/cron.hourly/ 由于anacron调用,有补跑能力

    ​ 5. /etc/cron.monthly/ 由于anacron调用,有补跑能力

    ​ 6. /etc/anacrontab 直接由anacron调用(本质上依然是依靠crond刷新/etc/cron.hourly/)

    任务是否会补跑

    anacron补跑的原理

    [root@localhost cron.hourly]# cd /var/spool/anacron/
    [root@localhost anacron]# ls
    cron.daily  cron.monthly  cron.weekly  # anacron是如何知道有没有补跑?在相应周期anacron跑完之后,会更新对应文件,如果文件小于对应周期,则不补跑,否则,补跑并且结束后更新此文件

    哪些任务会被补跑

    仅被anacron管理的任务才会自己补跑,即/etc/cron.daily/,/etc/cron.monthly/,/etc/cron.weekly/下放入的脚本会补跑,其余均不会补跑。

    另一个可以定时操作的服务

    Systemd 中的Timer Unit不仅可以做到微秒级的定时,还原生支持失败重试

    [root@localhost cron.daily]# systemctl list-timers
    NEXT                        LEFT          LAST                        PASSED    UNIT                         ACTIVATES
    Sun 2026-07-26 21:08:23 CST 1h 0min left  Sun 2026-07-26 19:48:01 CST 19min ago dnf-makecache.timer          dnf-makecache.service
    Mon 2026-07-27 00:00:00 CST 3h 52min left -                           -         logrotate.timer              logrotate.service
    Mon 2026-07-27 19:30:25 CST 23h left      Sun 2026-07-26 19:30:25 CST 37min ago systemd-tmpfiles-clean.timer systemd-tmpfiles-clean.service

    dnf-makecache.timer(元数据缓存更新)

    logrotate.timer(日志切割)

    systemd-tmpfiles-clean.timer(临时文件清理)

  • Linux管道和重定向

    proc虚拟文件系统

    /proc 是 Linux 系统中一个非常特殊的虚拟文件系统(被称为 procfs),通过直接读取 /proc 里的文件,来获取操作系统当前的运行状态、硬件信息以及进程数据。

    他有两大核心能力

    查看系统和硬件信息

    有很多常用的 Linux 命令(比如 top, free, lscpu),它们的底层数据其实都是直接从 /proc 文件夹里读出来的。

    /proc/cpuinfo:查看 CPU 的详细型号、核心数、缓存等。

    /proc/meminfo:查看内存的具体使用情况(free 命令的数据来源)。

    /proc/version:查看 Linux 内核版本和编译信息。

    /proc/uptime:查看系统从开机到现在运行了多久。

    查看进程信息

    ​ 1. 如果你在 /proc 下输入 ls,会看到密密麻麻的纯数字文件夹。这些数字其实就是系统的 PID(进程 ID)。

    每一个运行中的程序,都会在这里有一个对应的数字目录。

    ​ 2. 比如进程 PID 是 1234,那么 /proc/1234/ 目录下就记录了这个进程的一切:它是由哪个命令启动的(cmdline)、它的可执行文件绝对路径是什么(exe 软链接)、它打开了哪些文件句柄(fd/ 目录)等。

    ​ 3. 一旦进程结束,对应的数字文件夹就会立刻自动消失。

  • Linux基础-进程管理

    查看配置

    cpu信息查看

    [root@localhost ~]# lscpu
    Architecture:                x86_64  #架构
      CPU op-mode(s):            32-bit, 64-bit  
      Address sizes:             45 bits physical, 48 bits virtual
      Byte Order:                Little Endian
    CPU(s):                      2    # sockect(插槽)*core per socket * thread per core
      On-line CPU(s) list:       0,1
    Vendor ID:                   GenuineIntel
      BIOS Vendor ID:            GenuineIntel
      Model name:                Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz  #cpu型号
        BIOS Model name:         Intel(R) Core(TM) i5-1035G1 CPU @ 1.00GHz
        CPU family:              6
        Model:                   126
        Thread(s) per core:      1
        Core(s) per socket:      1
        Socket(s):               2
        Stepping:                5
        BogoMIPS:                2380.78
        Flags:                   fpu vme de pse tsc msr pae mce cx8 apic sep mtrr pge mca cmov pat pse36 clflush mmx fxsr sse sse2 ss syscall nx pdpe1gb
                                  rdtscp lm constant_tsc arch_perfmon rep_good nopl xtopology tsc_reliable nonstop_tsc cpuid tsc_known_freq pni pclmulqd
                                 q ssse3 fma cx16 pcid sse4_1 sse4_2 x2apic movbe popcnt tsc_deadline_timer aes xsave avx f16c rdrand hypervisor lahf_lm
                                  abm 3dnowprefetch ssbd ibrs ibpb stibp ibrs_enhanced fsgsbase tsc_adjust bmi1 avx2 smep bmi2 erms invpcid avx512f avx5
                                 12dq rdseed adx smap avx512ifma clflushopt avx512cd sha_ni avx512bw avx512vl xsaveopt xsavec xgetbv1 xsaves arat avx512
                                 vbmi umip pku ospke avx512_vbmi2 gfni vaes vpclmulqdq avx512_vnni avx512_bitalg avx512_vpopcntdq rdpid fsrm md_clear fl
                                 ush_l1d arch_capabilities
    Virtualization features:   #虚拟化
      Hypervisor vendor:         VMware
      Virtualization type:       full
    Caches (sum of all):
      L1d:                       96 KiB (2 instances)
      L1i:                       64 KiB (2 instances)
      L2:                        1 MiB (2 instances)
      L3:                        12 MiB (2 instances)
    NUMA:
      NUMA node(s):              1
      NUMA node0 CPU(s):         0,1
    Vulnerabilities:
      Gather data sampling:      Unknown: Dependent on hypervisor status
      Indirect target selection: Mitigation; Aligned branch/return thunks
      Itlb multihit:             KVM: Mitigation: VMX unsupported
      L1tf:                      Not affected
      Mds:                       Not affected
      Meltdown:                  Not affected
      Mmio stale data:           Vulnerable: Clear CPU buffers attempted, no microcode; SMT Host state unknown
      Reg file data sampling:    Not affected
      Retbleed:                  Mitigation; Enhanced IBRS
      Spec rstack overflow:      Not affected
      Spec store bypass:         Mitigation; Speculative Store Bypass disabled via prctl
      Spectre v1:                Mitigation; usercopy/swapgs barriers and __user pointer sanitization
      Spectre v2:                Mitigation; Enhanced / Automatic IBRS; IBPB conditional; PBRSB-eIBRS SW sequence; BHI SW loop, KVM SW loop
      Srbds:                     Unknown: Dependent on hypervisor status
      Tsa:                       Not affected
      Tsx async abort:           Not affected

    内存

    [root@localhost ~]# free -h
                   total        used        free      shared  buff/cache   available
    Mem:           3.5Gi       501Mi       2.6Gi       9.0Mi       739Mi       3.0Gi
    Swap:          3.9Gi          0B       3.9Gi

    磁盘

    [root@localhost ~]# df -Th
    Filesystem           Type      Size  Used Avail Use% Mounted on
    devtmpfs             devtmpfs  4.0M     0  4.0M   0% /dev
    tmpfs                tmpfs     1.8G     0  1.8G   0% /dev/shm
    tmpfs                tmpfs     725M  9.1M  716M   2% /run
    /dev/mapper/rlm-root xfs        37G  2.4G   35G   7% /
    /dev/nvme0n1p1       xfs       960M  256M  705M  27% /boot
    /dev/mapper/rlm-home xfs        19G  161M   18G   1% /home
    tmpfs                tmpfs     363M     0  363M   0% /run/user/0 

    内核信息

    cat /etc/os-release
    uname -a
    hostnamectl

    进程是什么

    1.基本概念

    ​ ● 进程是运行中的程序

    ​ ● 程序是静态文件,保存在硬盘上

    ​ ● 进程是程序运行的实例,是动态的,保存在内存中。有生有死

    [root@localhost ~]# file /bin/date    # 程序文件
    /bin/date: ELF 64-bit LSB pie executable, x86-64, version 1 (SYSV), dynamically linked, interpreter /lib64/ld-linux-x86-64.so.2, BuildID[sha1]=1b8568b41767b3c81e4080e90838bfdb24ca2e90, for GNU/Linux 3.2.0, stripped
    [root@localhost ~]# /bin/date         # 执行后产生进程
    2026年 07月 08日 星期三 10:14:41 CST
    [root@localhost ~]# ps aux | grep date   # 通过ps命令可以看到这个进程
    root        1536  0.0  0.0 221696  2604 pts/0    S+   10:14   0:00 grep --color=auto date

    2. pid/ppid/进程树

    进程也是分父子关系的,子进程都由父进程创建出来的

    pid:进程唯一识别号,类似身份证号

    ppid:父进程唯一识别号

    所有的进程的祖先是systemd(pid=1)的进程

    [root@localhost ~]# echo $$    #查看当前shell进程号
    1440
    [root@localhost ~]# ps -ef | grep 1440    #查看当前shell父进程号
    UID          PID    PPID  C STIME TTY          TIME CMD
    root        1440    1439  0 10:13 pts/0    00:00:00 -bash
    root        1542    1440  0 10:19 pts/0    00:00:00 ps -ef
    root        1543    1440  0 10:19 pts/0    00:00:00 grep --color=auto 1440
    [root@localhost ~]# pstree -p   #查看进程树,带上进程号
    systemd(1)─┬─NetworkManager(909)─┬─{NetworkManager}(910)
               │                     └─{NetworkManager}(911)
               ├─agetty(930)
               ├─auditd(826)───{auditd}(827)
               ├─chronyd(862)
               ├─crond(928)
               ├─dbus-broker-lau(852)───dbus-broker(853)
               ├─firewalld(856)───{firewalld}(908)
               ├─irqbalance(857)───{irqbalance}(863)
               ├─rsyslogd(943)─┬─{rsyslogd}(967)
               │               └─{rsyslogd}(971)
               ├─sshd(917)─┬─sshd(1423)───sshd(1439)───bash(1440)───pstree(1546)
               │           └─sshd(1428)───sshd(1470)───sftp-server(1471)
               ├─systemd(1429)───(sd-pam)(1431)
               ├─systemd-journal(725)
               ├─systemd-logind(858)
               └─systemd-udevd(737)

    查看进程号为1的进程

    [root@localhost ~]# ps -p 1
        PID TTY          TIME CMD
          1 ?        00:00:01 systemd

    3. 前台进程和守护进程

    前台进程:绑定终端,关闭终端就没了,使用ps aux查看基础进程,tty列一般是有值的,比如(pts/0)

    守护进程:独立运行,与终端无关,tty列一般是?,比如后续学到的各种服务都是守护进程状态运行,nginx,sshd等

    image-20260721184305369

    ==总结==: 是的,在实际运维视角中,除了用户登录产生的bash交互进程和它的子进程之外,systemd下挂的其余长期后台进程,几乎全都是守护进程,并且绝大多数都可以用 systemctl管理。

    Daemon 是“脱离终端控制、在后台长期运行、为系统提供特定服务”的进程。

    进程查看和排查工具

    1. ps aux

    a:显示所有终端下的进程,包括其他用户的进程(而不只是当前终端的)。

    u:以面向用户的格式输出,显示用户名、CPU 和内存使用率等详细字段。

    x:显示没有控制终端的进程(即后台守护进程,如 systemd、nginx 等)。

    0. top

    是 Linux 的实时系统监测工具,主要监控 CPU、内存和进程这三块

    image-20260721192736799

    [root@localhost ~]# ps aux
    USER         PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
    root           1  0.2  0.4 108308 16556 ?        Ss   21:13   0:01 /usr/lib/systemd/systemd --switched-root --system --deserialize 31
    root           2  0.0  0.0      0     0 ?        S    21:13   0:00 [kthreadd]
    root           3  0.0  0.0      0     0 ?        S    21:13   0:00 [pool_workqueue_]
    

    ==总结==:

    深入理解为什么linux和windows的程序互相跑不了

    • 二进制文件格式不同

    image-20260721185645195

    Linux 内核只认 ELF 格式,Windows 内核只认 PE 格式——它们各自按自己”看得懂”的方式去读二进制文件,读不懂就拒绝执行。这就是最根本、最直接的不兼容原因。


    列参数解析见课件

    下面先不学

    2. stat常见状态码(目前遇不到)

    3. STAT 状态码速查(最常遇到的几个)

    R:正在运行或处于运行队列中(可运行)。

    S:可中断的睡眠(等待某个事件完成,最常见)。

    D:不可中断的睡眠(通常在等待 I/O,如磁盘读写,此时不能轻易 kill)。

    Z:僵尸进程(子进程已退出,但父进程未回收,若大量堆积需处理)。

    T:暂停或被跟踪(如按了 Ctrl+Z 暂停的任务)。

    后缀附加符(如 S+、Ss):

    +:前台进程组(在前端运行)。

    s:会话领导者(通常为首进程)。

    l:多线程进程。

    3. 示例

    # 造一个T状态
    [root@rocky ~]# vim test.txt
    # 按 Ctrl+Z
    [root@rocky ~]# ps aux | grep vim       # STAT = T
    
    # ⭐找CPU最高的10个进程(生产最常用)   -%cpu是根据cpu递减,不加-就是递增
    [root@rocky ~]# ps aux --sort -%cpu | head -11
    
    # ⭐找内存最高的10个进程 -rss是根据rss递减的意思,不加-就是递增
    [root@rocky ~]# ps aux --sort -rss | head -11
    
    # 以树形展示
    [root@rocky ~]# ps auxf
    
    # 自定义显示格式,知道就行,不作要求
    [root@localhost ~]# ps -axo user,pid,ppid,%mem,%cpu,command --sort -%cpu
    这个新人需要知道吗

    image-20260721190116968

    4. 查看进程pid的方式汇总

    [root@localhost ~]# cat /run/sshd.pid 
    [root@localhost ~]# ps -aux |grep sshd
    [root@localhost ~]# pgrep -l sshd
    [root@localhost ~]# pidof sshd

    进程控制与实时监控

    1. top命令

    行关键字段怎么看
    第1行load average1分钟/5分钟/15分钟负载,≈CPU核心数算正常
    第2行Tasks(就相当于进程)重点关注 zombie 是不是0
    第3行%Cpuus(应用占用)、wa(IO等待,高说明磁盘慢)
    进程列表%CPU/%MEM/COMMAND⭐看谁占资源多

    重点交互命令

    按键功能
    P⭐按CPU排序
    M⭐按内存排序
    c显示完整命令
    q退出
    s改刷新间隔

    其他选项参考课件

    示例见课件部分

    2. kill命令

    编号信号名作用使用场景
    1SIGHUP重新加载配置改完配置文件不想重启
    9SIGKILL强制终止⚠️最后手段
    15SIGTERM优雅终止(默认)⭐首选!

    ==-15:礼貌请进程”下班”,进程可保存数据、释放资源==

    -9:内核直接”拖走”,进程来不及善后,可能丢数据、产生僵尸

    准则:能用-15就不用-9

    # 示例
    [root@rocky ~]# ping baidu.com > /dev/null &
    [1] 12345
    [root@rocky ~]# kill -15 12345      # 优雅终止
    [root@rocky ~]# kill -9 12345       # 强制终止(-15杀不掉时用)

    3. pkill批量杀

    # kill是精准狙击(要PID),pkill是地毯式轰炸(按名字)
    [root@rocky ~]# pkill ping                # 杀掉所有ping
    [root@rocky ~]# pkill -u appuser          # 杀掉某用户所有进程
    [root@rocky ~]# pkill -9 -t pts/1         # 踢掉某终端用户

    其他示例见课件

    进程优先级

    进程调度策略

    cls 显示值内核常量类型使用场景
    TSSCHED_OTHER / SCHED_NORMAL普通(默认)绝大多数业务进程,CFS 完全公平调度
    FFSCHED_FIFO实时(先入先出)必须立即完成且不主动让 CPU 的任务

    nice和pr

    Nice值:这是进程的“让行意愿”。Nice值越高(越“善良”),越主动给别人让出执行权;Nice值越低(越“霸道”),越爱插队,想着优先执行

    PR值:这是内核的最终调度优先级。内核会根据CPU实时负载强行调整顺序,不是完全听nice值

    pr和nice的关系

    再调度策略为SCHED_NORMAL时,top命令中的PR和NI列一定满足以下公式

    PR = 20 + NI

    而PR值是回被内核动态调整的,如果想要看动态的值,使用ps命令查看pri列

    # 这也是查看优先级常用命令
    [root@192 ~]# ps -axo pid,command,nice,cls --sort=-nice  # -o参数定义列格式
        PID COMMAND                      NI CLS
         43 [khugepaged]                 19  TS
         42 [ksmd]                        5  TS
          1 /usr/lib/systemd/systemd --   0  TS
          2 [kthreadd]                    0  TS
          3 [pool_workque&ue_]             0  TS
         10 [kworker/u512:0-events_unbo   0  TS
         12 [kworker/u512:1-netns]        0  TS
         13 [rcu_tasks_kthre]             0  TS

    调整正在运行的进程

    #终端1
    [root@192 ~]# vim
    #终端2
    [root@192 ~]# ps -axo command,pid,nice |grep vim
    vim                           12648   0
    grep --color=auto vim         12652   0
    [root@192 ~]# renice -20 -p 12648
    12648 (process ID) 旧优先级为 0,新优先级为 -20
    [root@192 ~]# ps -axo command,pid,nice |grep vim
    vim                           12648 -20
    grep --color=auto vim         12656   0

    调整正在运行的进程

    #终端1
    [root@192 ~]# vim
    #终端2
    [root@192 ~]# ps -axo command,pid,nice |grep vim
    vim                           12648   0
    grep --color=auto vim         12652   0
    [root@192 ~]# renice -20 -p 12648
    12648 (process ID) 旧优先级为 0,新优先级为 -20
    [root@192 ~]# ps -axo command,pid,nice |grep vim
    vim                           12648 -20
    grep --color=auto vim         12656   0

    启动时指定优先级

    # 终端1
    [root@192 ~]# nice -n 19 vim 
    # 终端2
    [root@192 ~]# ps -axo command,pid,nice |grep vim
    vim                           12657  19
    grep --color=auto vim         12661   0

    实践部分

    nice不要调成-20,可能会导致ssh都无法连上去

    一般不会太关注nice,==nice只用作微调,因为大部分业务场景都容器化,cpu资源基本由cgroups来做限制==

    后台管理

    jobs

    不能用作部署服务,终端关闭,任务会被终止

    nohup

    见课件示例

    系统服务管理

    定义见课件

    [root@192 ~]# pstree -p
    systemd(1)─┬─NetworkManager(907)─┬─{NetworkManager}(908)
               │                     └─{NetworkManager}(909)
               ├─auditd(823)───{auditd}(824)
               ├─chronyd(862)
               ├─crond(929)
               ├─dbus-broker-lau(853)───dbus-broker(854)
               ├─firewalld(857)───{firewalld}(906)
               ├─irqbalance(858)───{irqbalance}(863)
               ├─login(933)───bash(1432)
               ├─ping(12690)
               ├─rsyslogd(941)─┬─{rsyslogd}(970)
               │               └─{rsyslogd}(973)
               ├─sshd(922)─┬─sshd(12693)───sshd(12698)───bash(12700)───pstree(12786)
               │           └─sshd(12697)───sshd(12731)───sftp-server(12732)
               ├─systemd(1423)───(sd-pam)(1425)
               ├─systemd-journal(726)
               ├─systemd-logind(859)
               └─systemd-udevd(738)

    核心命令

    常用命令

    systemctl start   name.service    # 启动
    systemctl stop    name.service    # 停止
    systemctl restart name.service    # 重启
    systemctl reload  name.service    # ⭐重载配置(不停服)
    systemctl status  name.service    # ⭐查看状态

    开关机启动相关

    systemctl enable  name.service    # ⭐开机自启
    systemctl disable name.service    # 取消自启
    systemctl is-enabled name.service # 检查是否自启

    查看所有服务

    systemctl list-units --type service --all      # 所有服务状态
    systemctl list-unit-files --type service       # 查看是否开机自启
  • Linux基础-文件权限

    文件管理前置基础知识

    image-20260715194729459

    image-20260715195027375

    浏览器本质

    浏览器不管怎么变都是用的chrome的开源内核,然后套皮,内核都一样的所以就用edge或者chrome就行了


    命令行与操作系统系统调用交互的本质

    image-20260715200935250


    image-20260715201201126

    ==总结==

    Linux交互本质

    image-20260715201645272


    image-20260715202527575

    命令行与shell

    命令行和脚本并非两个割裂的工具,而是同一个Shell语言在时间维度上的前后衔接:

    • 命令行 = 实时调试(Debugging)平台:
      当你面对一个复杂任务(比如批量重命名、日志过滤)时,你不会直接去写一个几十行的脚本——因为那样效率太低,且一旦报错难以定位。你的第一反应是在命令行里逐条敲击指令,实时观察每一条的输出结果。这个过程中,你其实是在利用命令行的即时反馈机制,对参数、管道、正则表达式进行现场调试。发现不对,立刻按上箭头修改重试,直到这一条指令的输出完全符合预期。
    • 脚本 = 调试结果的固化(Solidification):
      当你在命令行中成功调试出那几条关键的指令后,你按 Ctrl+C 清屏,然后输入 vim script.sh。你把刚才在命令行中验证通过的指令逐条粘贴进去,并加上必要的 if 判断或 for 循环。这个动作就是固化——把你通过调试获得的、正确的“单条指令碎片”,组装成一个永久保存的、可重复执行的“自动化流程”。

    定义“调试”和“固化”在Linux交互中的角色

    环节 核心动作 本质意义
    调试(命令行) 手敲 → 看输出 → 改参数 → 再看输出 利用交互式的试错环境,将不确定的语法和参数调整为确定正确的状态
    固化(脚本) 复制粘贴 → 保存 → 赋予执行权限 → 定时/触发执行 将调试成功的瞬时操作,转化为持久的文本资产,脱离人工干预

    总结(结合调试与固化)

    命令行是Shell语言的“调试器”——它提供即时反馈,让你在现场反复测试、修正单条指令的逻辑和参数,直到结果无误。

    Shell脚本是命令行调试成果的“固化容器”——它将你在命令行中反复调试通过的指令集合,以文本文件的形式永久保存,并赋予自动化执行的能力(如定时任务、开机自启)。

    两者的协作流程:在命令行中调试 → 确认指令正确 → 粘贴进脚本固化 → 重复使用无需再调试。命令行是“草稿纸”,脚本是“正式出版文档”。

    ==总结==:

    image-20260724082714340

    image-20260724082836232


    VMware 软件

    image-20260715221200542


    image-20260715221312554


    虚拟机网络连接模式

    image-20260716135722236

    VMware软件创造虚拟机和ISO(镜像源文件)关系






    VMware 提供”硬件舞台”,ISO 提供”系统剧本”。







    1. ISO在VMware里的挂载什么意思 ?

    挂载 ISO 就是把那个 .iso文件虚拟成一张光盘,塞进虚拟机的光驱(CD/DVD)里。

    挂载成功的标志(两个复选框必须同时满足):

    ​ ✅ “已连接” — 相当于光盘已经塞进光驱里了。

    ​ ✅ “启动时连接” — 相当于开机时光驱是通电可读的。

    如果只设了ISO路径但没勾这俩,虚拟机开机时根本不知道光驱里有盘,就会直接跳过光驱去尝试网络启动。

    1. 启动顺序决定了先读谁

    虚拟机的 BIOS 里有个启动顺序(Boot Order),告诉它开机先检查哪个设备:

    光驱(CD-ROM)→ 硬盘(Hard Disk)→ 网卡(Network)

    • 顺序正常 → 先读光驱,发现有ISO → 开始安装系统。
    • 光驱没盘或没连接 → 跳转到硬盘(空的)→ 跳转到网卡(找不到PXE服务器)→ 最终报错 “Operating System not found”。

    你之前所有问题的根源,就是光驱被跳过了,所以一路走到网卡然后失败。


    虚拟机快照

    快照的创建

    在创建快照的时候,一定要关机了以后再拍摄快照,不要在开机的状态下创建快照。

    关机命令:

    poweroff

    创建快照:

    在上方点击虚拟机,找到快照,拍摄快照,然后起个名字,最后点击拍摄快照。我们的快照就创建好了

    image-20260716213223221

    image-20260716213358944

    快照的使用

    如果我们想要回复到某一个快照的时候,我们还是在上方虚拟机,快照,然后选择恢复到快照即可。

    image-20260716213542400

    远程管理Linux服务器

    通过电脑远程连接服务器进行管理,所以我们在后续学习的时候,为了方便,全部使用远程连接。

    Linux 远程连接命令行工具有很多:







    首先查看虚拟机的IP地址,也就是 Linux 服务器的 IP 地址,登录进虚拟机之后输入ip address可以查看

    image-20260716213930883

    这边可以看到本次安装的 RockyLinux 操作系统获取到的IP地址是 192.168.88.103 每个人装的虚拟机获取的 IP 地址可能是不一样的,需要仔细看清楚。

    在连接之前,我们需要在 RockyLinux 上设置一下,让它允许通过 root 用户远程连接进来

    [root@localhost ~]# echo "PermitRootLogin yes" >> /etc/ssh/sshd_config
    [root@localhost ~]# systemctl restart sshd

    image-20260717091113617

    image-20260717091221855

    两个网卡功能

    网卡全程作用判断标准通信标准
    lo环回网卡(Loopback)检验本机 TCP/IP 协议栈是否完整、内核网络功能是否正常ping 127.0.0.1 通 → 内核网络模块 OK仅限于本机内部,不经过任何物理线路
    ens160物理网卡(或虚拟物理网卡)提供本机与外部的网络通信能力(连接局域网、路由器、互联网)ping 网关 通→ 网卡驱动、IP配置、物理链路 OK本机 ↔ 外部世界(其他电脑、路由器、互联网)

    MobaXterm

    MobaXterm = 黑框框(命令行) + 文件管理器(可视化),让你在 Windows 上操作 Linux 服务器时,既有“键盘侠”的功力,又有“鼠标党”的便利。虚拟机本身还是那个纯命令行的 Linux,但你的操作体验已经从“纯盲打”升级成了“半图形化”。


    ==总结==

    远程操作 Linux 服务器,本质上是基于 TCP/IP 网络,通过 SSH 协议(Secure Shell)建立一条加密的命令行通道,利用 IP 地址在互联网中定位到目标主机,利用 端口号(SSH 默认是 22)找到主机上对应的 SSH 服务进程,最后以用户名和密码(或密钥)作为身份凭证,完成远程登录和操作的过程。

    需要注意的是:SSH 和 HTTP/HTTPS 是平级关系,它们都是运行在 TCP/IP 协议之上的应用层协议,只是分工不同——SSH(端口 22)负责加密的远程命令行交互,HTTP/HTTPS(端口 80/443)负责网页数据传输。它们是“兄弟”关系,而非“父子”关系。因此,“SSH 是基于 HTTP 的”这种说法是错误的。

    至于“同 IP 不同端口对应不同功能”的理解,完全正确。一台服务器只有一个 IP 地址,但可以开放多个端口,每个端口背后运行着不同的服务(如 22→SSH,80→Web,3306→MySQL),通过指定不同端口号,就能访问同一台服务器上的不同功能。

    Linux命令行

    初识shell

    Shell 是系统的用户界面,提供了用户与内核进行交互操作的一种接口。它接收用户输入的命令并把它送入内核去执行。实际上 Shell 是一个命令解释器,它解释用户输入的命令并且把用户的意图传达给内核。(可以理解为用户与内核之间的翻译官角色)

    image-20260717102302355

    我们可以使用 Shell 实现对Linux系统的大部分管理,例如:

    • 文件管理
    • 用户管理
    • 权限管理
    • 磁盘管理
    • 软件管理
    • 网络管理

    使用 Shell 的两种方式

    • 交互式命令行
      默认等待用户输入命令,输入一行回车后执行一行命令
      适合少量的工作
    • Shell 脚本
      将需要执行的命令和逻辑判断语句都写入一个文件后执行该文件
      适合完成复杂,重复性工作

    ==总结==:我们用的就是bashshell,首个命令都是应用程序,后面是参数


    文件系统管理

    讲解以课件为核心,重点:

    ​ ● linux系统路径特点,相对路径和绝对路径

    ​ ● 文件系统操作命令

    image-20260717190604804

    创建文件项目先都放在以/root目录的路径下

    image-20260717191430002

    ==总结==:~ 代表/root目录


    常用命令

    Linux 常见命令比较多,这边只列出初学者最常用的部分命令,大家可以根据命令有意去进行练习。

    注意 Linux 会准确的识别出命令的大小写,所以大家需要注意大小写的问题。命令选项和参数之间是用空格进行分隔,请大家在输入的时候注意不要缺失空格。

    学习 Linux 最重要的就是以下三个方面

    1. 命令的积累
    2. 原理的掌握
    3. 大量的实战

    命令大全

    分类命令**(*低频)**核心作用最高频参数工作中最典型的实例
    基础操作ls列出当前目录内容-alh 由三个分开的参数组合成 -a 就是参数als -alh # 以人类可读大小显示当前目录所有文件详情
    cd切换目录cd /var/log/ # 切换到日志目录 ; cd .. # 回到上级目录 ; cd # 直接回家目录
    pwd显示当前路径pwd # 输出如 /home/user/project,确认自己在哪
    clear清屏clear # 或直接按 Ctrl+L,让屏幕变干净
    echo打印输出内容-eecho “Hello Linux” # 输出字符串 ,echo $PATH # 查看环境变量值
    poweroff关机poweroff # 关闭服务器(虚拟机里常用)
    reboot重启reboot # 重启服务器
    whoami查看当前用户名whoami # 输出 root 或普通用户名
    history查看历史命令-c 数字history 10 #显示最近执行过的10条命令
    help查看内置命令帮助help cd # 查看 cd 命令的用法(针对bash内置命令)
    man查看命令手册man ls # 打开ls的完整手册,按 q 退出
    文件系统管理touch创建空文件/更新时间戳touch app.log # 创建一个空日志文件
    mkdir创建目录-pmkdir -p project/src/main # 一次性创建多级目录
    cp复制文件/目录-r -icp -r /etc/nginx/ ./backup/ # 递归复制整个nginx目录到当前目录下的backup
    mv移动/重命名文件-imv app.log app_old.log # 重命名日志文件mv app.log /tmp/ # 移动文件到/tmp
    rm删除文件/目录-r -f -rfrm -rf /tmp/cache/ # 强制删除cache目录(此操作不可恢复!)rm app.log # 删除单个文件
    cat查看完整文件内容-ncat -n /etc/hosts # 显示hosts文件内容并带行号
    tail查看文件尾部-f -ntail -f /var/log/nginx/access.log # 极高频:实时滚动查看nginx访问日志
    less(*)分页查看文件,极快加载超大文件less /var/log/messages # 分页查看系统日志,按空格翻页,按/搜索
    head(*)查看文件头部-nhead -n 3 /etc/passwd # 查看passwd文件前3行
    grep搜索文本内容-v -E -Agrep “ERROR” app.log # 在日志中找所有ERROR行grep -v “^#” /etc/nginx/nginx.conf # 排除注释行看有效配置
    unzip解压 .zip 文件-dunzip web.zip -d /var/www/html/ # 解压到指定目录
    zip压缩成.zip文件-rzip -r mydir.zip myfolder/ # 递归压缩myfolder文件为mydir.zip文件
    tar打包/解压 .tar.gz-czvf -xzvf -tftar -czvf backup.tar.gz /var/log/ # 打包压缩日志目录tar -xzvf backup.tar.gz # 解压tar -xzvf backup.tar.gz -C /root/backup #解压到指定目录
    文本编辑vim / vi终端文本编辑器vim /etc/hosts # 打开配置文件按 i 编辑 → 按 Esc → 输入 :wq 保存退出放弃修改按 :q!
    nano(*)简单文本编辑器nano ~/.bashrc # 用nano编辑环境变量文件底部有快捷键提示:^X退出,^O保存
    文件下载curl发送HTTP请求/下载-O -o -Lcurl -O https://example.com/file.zip # 下载并保持原名curl -L -o nginx.tar.gz https://nginx.org/download/nginx-1.24.0.tar.gz # 跟随重定向下载并指定文件名
    wget下载文件-O -c -qwget https://example.com/bigfile.iso # 最直接下载wget -c https://example.com/bigfile.iso # 断点续传(下载中断后继续)
    环境变量alias给命令起别名-palias ll=’ls -lh’ # 以后输入ll等价于ls -lhalias rm=’rm -i’ # 让rm删除前先确认which ll # 可以反向查看ll的构成
    key=value [cmd]临时增加环境变量
    PATH可执行文件搜索路径echo $PATH # 查看当前PATH路径export PATH=$PATH:/opt/myapp/bin # 临时添加新路径到PATH
    bashrc等用户环境配置文件vim ~/.bashrc # 编辑用户环境配置source ~/.bashrc # 让配置立即生效
    /usr/bin系统命令存放目录which ls # 查看ls命令实际位置,通常输出 /usr/bin/ls
    export变量给子进程# 导出为环境变量export MY_NAME=”张三”# 现在子shell就能看到了bash -c ‘echo $MY_NAME’ # 输出:张三
    source在当前脚本执行命令常用于让 ~/.bashrc 中配置立即执行
    which查看命令完整路径which ll
    whereis查看命令位置whereis ip

    ==总结==:

    1. 参数就学固定组合就行,不用管小的遇到了问 ai
    2. man有用,查看命令手册,手册是详细介绍内容的,介绍查看的是什么
    # 为了让别名永久生效,可以将修改别名的命令写入 bashrc 文件,这个文件中的命令会在每次登陆命令行的时候执行
    [root@localhost ~]# echo "alias wl='ip address'" >> /.bashrc

    在 Linux shell 中,>> 是追加重定向操作符,用于将命令的输出(标准输出)追加到指定文件的末尾,而不会覆盖原有内容

    日常使用中,>> 非常常见,尤其是需要保留历史记录时,用它就对了

    image-20260717194313651

    ==注意==: /.bashrc是当前用户交互式 Bash Shell 的首选永久配置阵地。把别名、环境变量、函数写在这里,每次打开终端都会自动加载,且无需 sudo权限,只影响你自己。

    1. 文件操作
    • 蓝色就是文件夹 ;白色就是文件
    • 在project文件夹里创建文件,项目

    image-20260717195503457

    image-20260717200141030

    1. 复制文件

    image-20260717200029148

    1. 复制文件到别的文件夹

    image-20260717200627865

    image-20260717200716035

    ==注意==:-r可以递归复制,而linux快捷键直接把要复制的文件夹和里面的嵌套的都复制的,linux需要递归复制

    1. 一次创建多个目录(文件夹)

    image-20260717201122379

    image-20260717201215914

    [root@localhost ~]# mkdir /home/dir{1,2}
    1. mv (移动和重命名文件,目录)

    image-20260717201759656

    1. cat 查看文件/程序详细内容

    image-20260717202147741

    1. head和tail,tail非常重要

    image-20260717202927285

    image-20260717203002714

    1. grep过滤和文件结合

    image-20260717203606726

    1. wget和curl

    image-20260717204400776

    image-20260717204455328

    image-20260717204559685

    配置golang语言环境

    1. linux压缩与解压
    • 解压
    1. 为什么要“先建目录,再解压”?(3大好处)

    image-20260717220931029

    1. linux系统压缩文件zip压缩在linux,zip -r 自己命名的压缩包(名字自己命名) project(想要压缩的文件夹)

    image-20260717222336697

    image-20260717222543309

    压缩也把指定的文件目录压缩进去了,不只有文件

    1. tar工具解压缩

    tar -xzvf 包名 -C 目标目录 → 解压到指定目标目录(-C 必须大写)

    tar -xzvf 包名.tar.gz -C 目标目录








    image-20260717233911951

    压缩也是一样的方式

    解压成功

    image-20260717234013652


    文本编辑

    在 Linux 中只掌握文本查看是远远不够的,我们还需要掌握编辑文本文件。

    Linux 上也有图形化的文本编辑器,类似于 Windows 的记事本,但是很多时候我们只能用命令行来管理 Linux 操作系统,所以必须要掌握命令行的文本编辑器软件。

    目前常见的命令行文本编辑器

    • vim:具有程序编辑的能力,可以主动的以字体颜色辨别语法的正确性,方便程序设计。

    什么是Vim

    Vim 是从 vi 发展出来的一个文本编辑器。代码补完、编译及错误跳转等方便编程的功能特别丰富,在程序员中被广泛使用。 Vim 是一个纯命令行文本编辑器,很多文本编辑的功能都是通过键盘快捷键的方式完成,所以我们需要记住常用的键位。

    image-20260718131446522

    编辑模式







    环境变量

    定义

    什么是环境变量

    变量名 = 值

    PATH = /usr/bin:/usr/local/bin

    可以通过env命令查看所有的环境变量

    最重要的环境变量

    # 1. PATH —— 最重要!决定命令去哪找
    echo $PATH
    # /usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin
    
    # 2. HOME —— 当前用户的家目录
    echo $HOME     # /home/july
    

    临时和永久设置环境变量

    export MY_NAME="July"
    echo $MY_NAME    # July
    
    # 关掉终端就消失了!

    永久设置

    # 编辑 ~/.bashrc 或 ~/.bash_profile
    echo 'export MY_NAME="July"' >> ~/.bashrc
    source ~/.bashrc   # 让修改立即生效
    

    理解Path变量的增加

    export PATH=$PATH:/opt/my-tools/bin
    # 注意:是追加,不是覆盖!
    

    查看环境变量

    image-20260718175323201

    ==总结环境变量==(绝对正确):

    image-20260718183235589

    image-20260718183747788

    文件基本属性与文件查找

    文件时间

    [root@localhost ~]# export LANG="en_US.UTF-8"
    [root@localhost ~]# stat anaconda-ks.cfg
      File: anaconda-ks.cfg
      Size: 822             Blocks: 8          IO Block: 4096   regular file
    Device: fd00h/64768d    Inode: 101570610   Links: 1
    Access: (0600/-rw-------)  Uid: (    0/    root)   Gid: (    0/    root)
    Context: system_u:object_r:admin_home_t:s0
    Access: 2026-06-28 18:41:04.558360924 +0800
    Modify: 2026-06-17 15:42:50.534899118 +0800
    Change: 2026-06-17 15:42:50.534899118 +0800
     Birth: 2026-06-17 15:42:50.471875635 +0800
    

    时间格式解释: 2026-06-17 15:42:50.534899118 +0800(年-月-日 时-分-秒.纳秒 +时区偏移)UTC+8是东八区北京时间

    image-20260718133418797

    image-20260718133431285

    文件类型

    ls -al查看的文件信息,现阶段只需要知道:

    ​ ● -代表普通文件(文本文档,二进制文件,压缩文件,电影,图片等等)

    ​ ● d代表目录即可

    file也可以查看一个文件类型

    文件查找

    # 根据名称查找
    find /root -name test.txt # 查找/root目录下所有名称为test.txt的文件
    # 查找后处理
    find / -name learvim.txt -exec ls -alh {} ;  # 查找/目录下所有名字为learvim.txt文件,并ls -alh查看信息
    #{}代表占位, 是命令截至符
    

    ==总结==:

    image-20260718185317629

    1. image-20260718185343848

    用户权限管理

    在创建虚拟机时,系统根据你输入的【用户名】在 /etc/passwd 中分配并写死了一个唯一的 UID 数字(通常第一个普通用户为 1000)。而【密码】仅仅是被加密后存进 /etc/shadow 用于登录校验,它【完全不参与】UID 数字的生成和决定。

    image-20260718134812021

    1. “定死”的真实含义(计算机系的严谨表述) UID 一旦分配,默认永久固定:在 /etc/passwd 里,moonbit:x:1000:1000这一行写死了 1000。除非你用 usermod -u 2000 moonbit手动修改,否则永远不会变。

    2. Root 视角:虚拟机安装时的“默认规则”对 Root 不适用 你在虚拟机里如果全程用 Root,那么安装时 Linux 遵循的是这条铁律:

    • Root 用户根本不需要“分配”UID:Root 的 UID 0 是写在 Linux 内核源码里的(#define ROOT_UID 0)。只要系统存在,Root 就存在,永远占用 UID=0。
    • 你安装时输入的那个普通用户名(比如 moonbit)如果存在,系统才会从 1000 开始排。但如果你在安装时直接启用 Root 登录,或者安装后删掉了普通用户,你的整个系统只有一个超级用户(Root)。

    ​ 在你的机器上:不存在“第一个普通用户分配 1000”这个概念。系统启动后,内核直接识别 UID=0 为最高权限,所有的 /home/用户 名 目录都不存在,只有 /root 是唯一的家目录。

    1. Root 视角:登录流程链在你这里“省略了校验”
      既然你“这边都是 root”,登录流程会变成:

    “虚拟机启动后,你以 Root(用户名 root,UID=0)登录。系统直接将UID=0写入当前 Shell 进程的 PCB,完全不需要去 /etc/passwd里查询分配(因为 0 是硬编码),也不需要校验普通用户的身份。自此,该 Shell 启动的所有子进程都继承这个UID=0。由于你已经是最高权限,你执行命令时完全不需要 sudo——直接 vim /etc/passwd 就能改,直接rm -rf /就能把系统删光(千万小心)。”


    用户和用户组查看

    image-20260720090347275

    image-20260720090438571

    传统运维和云计算云原生

    从管理对象和运维逻辑两个角度:

    1. 管理对象的差异

    • 传统运维(管理服务器):管理的是“物理实体/虚拟机”。关注的是硬件状态(CPU温度、磁盘坏道、电源冗余)、操作系统版本、内核参数、以及中间件(如Nginx、MySQL)的安装路径和配置文件。服务器本身是“资产”,IP地址是固定的,主机名是有业务含义的。
    • 云原生管理(管理程序):管理的是“工作负载(Workload)”。关注的是Pod的数量、服务的副本数、容器镜像的版本标签、以及服务之间的依赖关系(服务网格)。服务器被抽象为“资源池”,IP是临时分配的(甚至Pod重启就会变),管理员不关心这台机器是Intel还是AMD,只关心它提供的计算、内存和存储容量是否充足。

    2. 运维逻辑(应对故障)的差异





    3 部署与变更的差异(附带补充,便于理解)

    • 传统运维:部署是“状态修改”。用脚本(Shell/Ansible)在现有服务器上拷贝代码、修改配置、重启进程。环境具有“累积性”,这台机器跑了3年,上面装过什么遗留包,谁也说不清。
    • 云原生管理:部署是“镜像替换”。服务器本身是纯净的(只装容器运行时),每次发布只是把旧版本的镜像下线,拉取新镜像启动新Pod。环境是“一次性”的,没有历史包袱,回滚就是瞬间切回旧镜像版本。

    ==总结==:

    传统运维把服务器当成“需要精心照顾的病人”,目的是让应用程序住得安稳;云原生管理把服务器当成“流水线上的标准零件”,目的是让应用程序在零件坏了时能瞬间换到新零件上继续运行,且全程无感知。


    Linux系统提权管理(sudo)标准操作规范:

    在标准的Linux系统中,普通用户默认是可以“读取”/etc目录下大部分文件的(如/etc/passwd),但默认是绝对“无法写入”或“创建文件”的。

    如果你现在连 ls /etc 都报错(Permission denied),说明你的系统权限被人为加固或误修改了。我们分三种情况来排查:

    1. 你想“修改”配置文件(最常见情况)

    比如你想改 /etc/hosts 或 /etc/ssh/sshd_config。 结论:这不是“访问不了”,而是“没有写权限”。

    • 原因:/etc 目录及其下的系统级配置文件,所有权默认属于 root:root,普通用户只有读(r–)权限,没有写(-w-)权限。
    • 解决方案:必须使用 sudo 提权。

    2. 用户提权

    1. 核心管理路径

    使用 /etc/sudoers.d/ 目录下的独立文件管理授权规则,而非直接修改主配置文件 /etc/sudoers。独立文件便于规则分类、回滚及删除,且修改后即时生效,无需重启服务。

    2. 文件命名规范

    /etc/sudoers.d/ 目录下的文件名不得包含点号(.)或波浪号(~),且不能有后缀名(如 .conf)。

    • 错误示例:mygroup.conf、rule.txt(系统会忽略此类文件)
    • 正确示例:mygroup、20_devops(建议使用数字前缀增强可读性)

    3. 授权规则语法(组级别)

    在规则文件中,使用百分号(%)前缀表示组。









    4. 规则编辑要求

    必须使用 visudo 命令编辑规则文件,以进行语法校验,防止因格式错误导致整个 sudo 机制失效。

    bash

    visudo -f /etc/sudoers.d/文件名

    5. 用户与组的管理策略









    6. 权限生效机制

    通过 usermod 修改组信息后,当前已建立的 SSH 会话不会自动加载新的组身份。

    • 操作要求:用户需执行 exit 退出当前会话并重新登录,或新建 SSH 连接,新的组权限及对应的 sudo 规则才会生效。

    文件权限管理

    U/G/O权限模型

    基础信息

    [root@localhost ~]# ls -al anaconda-ks.cfg.bak
    -rwxrwxrwx. 1 root root 838 Jun 28 19:03 anaconda-ks.cfg.bak

    img

    ==重点关注rwx,acl权限,属主和数组==

    image-20260720103517382

    ls -alh hello.c查看文件基本信息

    rwx对文件和目录的影响

    权限对文件的含义对目录的含义
    r (读)能看文件内容(cat)能看目录里有啥文件名(ls)
    w (写)能修改文件内容能新建/删除/重命名文件
    x (执行)能当作程序运行能进入该目录(cd)

    rwx的数字表达

    rwx每个位可以看作二进制位

    rwx=111=4+2+1=7
    r-x=101=4+0+1=5
    ---=000=0

    因此有时会有人说r=4,w=2,x=1就是上述二进制转换成10进制的含义

    默认情况下,新建的目录权限为755(rwxr-xr-x)自己全权,其他人可读可执行,新建的文件是644(rw-r–r–)自己可读写,其他人只读

    chown修改文件属主和属组

    基本语法

    chown [选项] 新属主:新属组 目标

    -R: 处理指定目录以及其子目录下的所有文件(递归执行,一定要确认目录是不是目标目录,否则容易P0!!!否则容易P0!!!否则容易P0!!!)

    命令格式作用示例
    chown user file只改属主chown nginx index.html
    chown :group file只改属组chown :www-data index.html
    chown user:group file同时改属主和属组chown nginx:www-data index.html
    chown user: file改属主,属组改成属主的默认组chown nginx: index.html

    将目录下的所有文件拥有者设置为user01,允许使用的组设置为it

    [root@localhost ~]# chown -R user01:it dir/*  # 注意,dir/*是匹配dir目录下所有文件,不包括dir
    [root@localhost ~]# chown -R user01:it dir/   # 包括dir自己

    ==总结==:

    一切以文件为中心

    image-20260720125351482

    image-20260720125436541

    image-20260720125624243

    image-20260720125651177

    image-20260720125717308


    image-20260720125748892

    image-20260720125807710

    image-20260720125825765


    image-20260720125843531

    image-20260720125904439


    chmod修改权限

    基本语法

    chmod [选项] 权限模式 目标文件/目录

    两种写法

    写法示例
    数字法chmod 755 script.sh
    符号法chmod u+x script.sh
    chmod u+x    file    # 属主加执行权限
    chmod g-w    file    # 属组去掉写权限
    chmod o+r    file    # 其他人加读权限
    chmod a+x    file    # 所有人(u+g+o)加执行权限

    示例见课件

    #递归改整个目录
    chmod -R 755 /app
    # 高危操作,一定要确保/app是你需要改的范围

    其余示例见课件


    文件ACL访问控制列表

    背景

    前面我们讲了传统的 u/g/o 权限模型,它有一个致命缺陷:只能管三类人。

    生产环境里,我们经常遇到这样的需求:”让张三临时看一眼日志,但别动别的”,传统模型做不到,这时候就该 ACL 出场了。

    所以u/g/o一般是通用的权限管理,而临时授权或者特批权限就需要acl来完成

    两个核心命令

    getfacl    # 查看ACL
    setfacl    # 设置ACL
    命令含义示例
    setfacl -m u:用户名:权限 目标给用户加ACLsetfacl -m u:zhangsan:rw- file
    setfacl -m g:组名:权限 目标给组加ACLsetfacl -m g:devops:r-x /data/
    setfacl -x u:用户名 目标删除特定用户的ACLsetfacl -x u:zhangsan file
    setfacl -b 目标删除所有ACLsetfacl -b file(恢复纯传统权限)
    setfacl -R 目标递归设置ACLsetfacl -R -m u:zhangsan:r– /app/logs/
    getfacl 目标查看ACLgetfacl /app/logs/

    案例

    ​ 1. 创建sre-team组,创建sre-pjw用户归属sre-team

    ​ 2. 配置sre-pjw密码,切换至sre-pjw

    ​ 3. 用root用户创建/home/sre-pjw/hello.c,写上c的hello world

    ​ 4. 用root撤销hello.c other用户的r权限

    ​ 5. 登陆至sre-pjw用户尝试读取hello.c,提示无权限

    ​ 6. 返回root,使用acl给sre-pjw临时开放可读权限

    ​ 7. 登录sre-pjw尝试查看sre-team

    ==案例流程是对的,包含权限管理和acl单个文件设定==

    [root@localhost project]# getfacl hello.c
    # file: hello.c
    # owner: root
    # group: root
    user::rw-
    group::r--
    other::---
    
    [root@localhost project]# setfacl -m u:sre-pjw:r hello.c
    [root@localhost project]# getfacl hello.c
    # file: hello.c
    # owner: root
    # group: root
    user::rw-
    user:sre-pjw:r--
    group::r--
    mask::r--
    other::---

    ==注意==:

    image-20260720160008408

    acl权限继承

    我希望/project后续创建的所有文件,都自动给sre-pjw读权限:使用d参数,针对目录设置默认acl规则

    # 设置默认ACL:未来新建的文件自动给zhangsan读权限
    [root@localhost ~]# setfacl -m d:u:sre-pjw:rwx /project/
    [root@localhost ~]# getfacl /project/
    getfacl: Removing leading '/' from absolute path names
    # file: project/
    # owner: root
    # group: root
    user::rwx
    group::r-x
    other::r-x
    default:user::rwx
    default:user:sre-pjw:rwx
    default:group::r-x
    default:mask::rwx
    default:other::r-x
    # 输出会多一行:
    # default:user:sre-pjw:rwx   ← 这个就是默认策略
    
    # 示例创建新的hello.py
    [root@localhost ~]# touch /project/hello.py
    [root@localhost ~]# ls -al /project/
    总用量 0
    drwxr-xr-x+  2 root root  37  7月  5 17:10 .
    dr-xr-xr-x. 19 root root 250  7月  5 16:43 ..
    -rw-r--r--.  1 root root   0  7月  5 16:43 hello.c
    -rw-rw-r--+  1 root root   0  7月  5 17:10 hello.py
    
    # 查看hello.py
    [root@localhost ~]# getfacl hello.py
    # file: hello.py
    # owner: root
    # group: root
    user::rw-
    group::r--
    other::r--
    
    # sre-pjw用户是可以正常创建的
    [sre-pjw@localhost ~]$ echo "print(1)" > /project/hello.py
    [sre-pjw@localhost ~]$ cat /project/hello.py
    print(1)
    #sre-zhangsan用户创建
    [root@localhost ~]# useradd sre-zhangsan -G sre-team
    # sre-zhangsan用户是无法创建的
    [sre-zhangsan@localhost ~]$ echo "aaa" > /project/hello.py
    -bash: /project/hello.py: 权限不够

    mask权限

    mask 权限,指的是用户或群组能拥有的最大 ACL 权限,也就是说,给用户或群组设定的 ACL 权限不能超过 mask 规定的权限范围,超出部分做无效处理。

    比如下方示例,mask::rw- 所有所有用户和组的最大权限就是rw,不会有x,getfacl的输出已经提示了,只有#effective:rw-,仅rw生效

    [root@192 project]# getfacl hello.py
    # file: hello.py
    # owner: root
    # group: root
    user::rw-
    user:sre-pjw:rwx                #effective:rw-
    group::r-x                      #effective:r--
    mask::rw-
    other::r--

    image-20260720185119031

    修改mask为rwx,再观察acl信息

    可以观察发现,确实不存在 #effective提示了

    [root@192 project]# setfacl -m m::rwx hello.py
    [root@192 project]# getfacl hello.py
    # file: hello.py
    # owner: root
    # group: root
    user::rw-
    user:sre-pjw:rwx
    group::r-x
    mask::rwx
    other::r--

    需要注意,如果改变属组常规权限,mask会随之改变,因此chmod会影响mask。日常运维操作,如果chmod改变了,要注意acl规则是否需要手动调整

    下图对比上图,如果g-x后,mask也减了x,对于sre-pjw,x权限就没了

    [root@192 project]# chmod g-x hello.py
    [root@192 project]# getfacl hello.py
    # file: hello.py
    # owner: root
    # group: root
    user::rw-
    user:sre-pjw:rwx                #effective:rw-
    group::r-x                      #effective:r--
    mask::rw-   
    other::r--

    image-20260720185809341

    ==总结==:

    image-20260720190105673

    特殊权限SUID/SGID/STICKY

    suid

    使用场景:让执行这个文件的用户,暂时获得文件属主的身份权限

    经典案例:/usr/bin/passwd

    [root@192 project]# ls -al /usr/bin/passwd
    -rwsr-xr-x. 1 root root 32656  5月 15  2022 /usr/bin/passwd
    #  ^
    #  这个s就是SUID,属主是root
    没有SUID有SUID
    普通用户执行 passwd → 以普通用户身份运行 → 无法修改 /etc/shadow(属主root,权限600)普通用户执行 passwd → 以root身份运行 → 可以修改 /etc/shadow

    使用注意事项:

    ​ 1. 只对二进制文件有效

    ​ 2. 谁拥有这个文件,执行者就变成谁

    ​ 3. 没x权限,SUID位加上也没用

    修改方式

    chmod u+s /project/hello.py
    chmod 4755 /project/hello.py # 前面的 4 = SUID

    sgid

    在该目录下新建的文件/目录,自动继承该目录的属组,而不是创建者的主组。

    文件上的SGID(不太常用)

    目录上的SGID(常用)

    经典案例:创建了一个/data/sre-team-share目录,我想让所有用户再此目录下创建的文件和目录都属于sre-team组

    使用root用户测试

    [root@192 ~]# ls -al
    ...
    -rw-r--r--.  1 root root     0  7月  5 17:09 hello.py
    drwxr-x---.  2 root root     6  7月  1 17:04 project
    ...
    
    [root@192 ~]# cd /data/sre-team-share/
    [root@192 sre-team-share]# mkdir root-test
    [root@192 sre-team-share]# chown :sre-team root-test
    [root@192 sre-team-share]# touch root-hello.txt
    [root@192 sre-team-share]# ls -al
    总用量 0
    drwxr-sr-x. 3 root sre-team 45  7月  7 21:32 .
    drwxr-xr-x. 3 root root     28  7月  7 21:27 ..
    -rw-r--r--. 1 root sre-team  0  7月  7 21:32 root-hello.txt  #文件属于sre-team
    drwxr-sr-x. 2 root sre-team  6  7月  7 21:31 root-test #目录属于sre-team

    修改方式

    chmod g+s file
    chmod 2755 dir(前面的 2 = SGID)

    sticky

    即使有目录的写权限,也只能删除/重命名属于自己的文件

    [root@192 sre-team-share]# ls -ld /tmp
    drwxrwxrwt. 11 root root 4096  7月  7 21:31 /tmp
    #        ^ 标识sticky

    修改方式

    chmod 1777 /tmp/ (前面的 1 = Sticky Bit)

    注意:sticky对root不生效!!!

    这是默认正文标识符号

    chattr文件属性

    与U/G/O和ACL都不同,chattr是作用于文件或文件目录的,与用户无关,只要设置了规则,所有用户都一样对待。

    示例:某一个重要文件,任何人不得删除

    # 1. 创建一个测试文件
    echo "hello" > test.txt
    chmod 777 test.txt   # 所有人都能读写执行
    
    # 2. 加上 i 属性(不可变)
    chattr +i test.txt
    
    # 查看属性
    [root@192 ~]# lsattr test.txt
    ----i----------------- test.txt
    
    # 3. 即使你是root,也动不了它
    echo "world" >> test.txt
    # 报错: bash: test.txt: Operation not permitted
    
    rm -f test.txt
    # 报错: rm: cannot remove 'test.txt': Operation not permitted
    
    # 4. 必须先把i属性去掉
    chattr -i test.txt
    # 现在才能正常操作

    重点:chattr 的权限检查在 UGO/ACL 之后执行,因此用户权限不管多大,都得遵守chattr属性

    只需要记住两个核心参数

    ​ ● -i 不可变(重要的数据文件)

    ​ ● -a 仅追加,不能修改和删除(日志文件)

    umask权限

    umask 是 Linux 给新文件/目录设置默认权限时的“减分项”或“遮罩”。它决定了“默认情况下,新建的文件/目录应该去掉哪些权限”。

    基础计算公式如下

    文件默认权限 = 666 - umask
    目录默认权限 = 777 - umask

    查看当前用于默认umask

    [root@192 ~]# umask # 后面跟上3为数字就是设置umask
    0022
    
    # 第一个0忽略
    umask = 0 2 2
            │ │ │
            │ │ └── 其他人(other):减掉 2(写权限 w)
            │ └──── 属组(group):减掉 2(写权限 w)
            └────── 属主(user):不减(0)
    
    所以:
      属主(user):不减任何权限 → rwx
      属组(group):减掉 w → r-x(即 rx)
      其他人(other):减掉 w → r-x(即 rx)

    创建文件和文件夹测试

    [root@192 ~]# touch umask-file
    [root@192 ~]# mkdir umask-dir
    [root@192 ~]# ls -al
    ...
    drwxr-xr-x.  2 root root     6  7月  7 21:56 umask-dir
    -rw-r--r--.  1 root root     0  7月  7 21:56 umask-file
    ...

    umask修改后再当前shell立即生效,重启后失效,如果想重启保持,需要写入配置文件

    [root@localhost ~]# vim /etc/profile
    + umask 002
    [root@localhost ~]# source /etc/profile        # 立即在当前shell中生效

    课件中的脚本含义:“不是系统用户(普通用户)”并且“主组名 = 用户名(用户有自己的私有组)”给umask给002,否则给022

    文件权限分析

    ls -al (u/g/o属主属组权限,特殊标志位,u[s] g[s] o[t])

    1.这个文件本身

    2.父级目录中上述权限(目录对于普通用户,rwx限制了ls,touch,rm,cd等操作)

    getfacl,查看此文件的acl列表

    lsattr 查看此文件的特殊属性标志


  • Linux软件包管理

    背景

    linus喜欢使用的linux发行版:fedora

    【官方双语】真·Linus来了! – 为Linux之父Linus Torvalds装机 / 两莱一机#linus谈科技】 https://www.bilibili.com/video/BV1ueS4BUEEn/?share_source=copy_web&vd_source=9d01159cb1b6afa8b969782aea8cb4c8

    软件包

    源码包(Source Package)
    ├── 人类可读的源代码
    ├── 需要编译工具转换
    ├── 优点:可定制、性能优化
    └── 缺点:编译、依赖复杂
    
    二进制包(Binary Package)
    ├── 已经编译好的机器码(指令集和操作系统)
    ├── 直接安装即可使用
    ├── 优点:安装快、依赖自动解决(yum)
    └── 缺点:版本固定、灵活性较低

    生活中的类比:

    点外卖:商家做好送上门 → 二进制包(直接安装使用)

    自己做饭:买菜→洗切→烹饪 → 源码包(需要编译)

    rockylinux中包格式

    RPM(Red Hat Package Manager)
    ├── 文件名格式:软件名-版本号-发布次数.架构.rpm
    ├── 示例:nginx-1.20.1-10.el9.x86_64.rpm
    │          ├── nginx      → 软件名称
    │          ├── 1.20.1     → 主版本号.次版本号.修订号
    │          ├── 10.el9     → 第10次发布,适配Rocky9
    │          └── x86_64     → 64位系统
    └── 特点:红帽系专用(RHEL/CentOS/Rocky/Alma)

    rocky中的管理工具变化

    RPM时代(90年代)
    └── rpm -ivh package.rpm
        └── 问题:不会自动解决依赖,被称为"依赖地狱"
    
    YUM时代(2003-2020)
    └── yum install package
        └── 改进:自动解决依赖关系
        └── 基于Python2开发
    
    DNF时代(2020-至今)
    └── dnf install package
        └── 改进:性能更好、依赖解析更快
        └── 基于Python3开发

    rocky9.7中所使用的yum其实就是dnf,所以大家到底使用dnf还是yum,根据自己喜好来

    [root@localhost ~]# which yum
    /usr/bin/yum
    [root@localhost ~]# ls -al /usr/bin/yum
    lrwxrwxrwx. 1 root root 5 11月  3  2025 /usr/bin/yum -> dnf-3
    [root@localhost ~]# which dnf
    /usr/bin/dnf
    [root@localhost ~]# ls -al /usr/bin/dnf
    lrwxrwxrwx. 1 root root 5 11月  3  2025 /usr/bin/dnf -> dnf-3

    image-20260724175923374

    命令实战

    # 查看版本,dnf是前台工具,软件安装还是依靠rpm命令
    [root@localhost ~]# dnf --version
    4.14.0
      Installed: dnf-0:4.14.0-31.el9.noarch at Wed 17 Jun 2026 07:39:51 AM GMT
      Built    : Rocky Linux Build System (Peridot) <releng@rockylinux.org> at Mon 03 Nov 2025 04:06:26 AM GMT
    
      Installed: rpm-0:4.16.1.3-39.el9.x86_64 at Wed 17 Jun 2026 07:39:39 AM GMT
      Built    : Rocky Linux Build System (Peridot) <releng@rockylinux.org> at Fri 31 Oct 2025 01:43:53 AM GMT

    查找软件包

    # 搜索想要安装的工具包,一般是自己想要安装一个工具包,但是不确定repo仓库中有没有,可以先搜索一下
    [root@localhost ~]# dnf search nginx
    Rocky Linux 9 - BaseOS                                                                                              6.5 MB/s |  11 MB     00:01
    Rocky Linux 9 - AppStream                                                                                           6.5 MB/s |  15 MB     00:02
    Rocky Linux 9 - Extras                                                                                              7.1 kB/s |  17 kB     00:02
    =========================================================== Name Exactly Matched: nginx ============================================================
    nginx.x86_64 : A high performance web server and reverse proxy server
    ========================================================== Name & Summary Matched: nginx ===========================================================
    nginx-all-modules.noarch : A meta package that installs all available Nginx modules
    nginx-core.x86_64 : nginx minimal core
    nginx-filesystem.noarch : The basic directory layout for the Nginx server
    nginx-mod-http-image-filter.x86_64 : Nginx HTTP image filter module
    nginx-mod-http-perl.x86_64 : Nginx HTTP perl module
    nginx-mod-http-xslt-filter.x86_64 : Nginx XSLT module
    nginx-mod-mail.x86_64 : Nginx mail modules
    nginx-mod-stream.x86_64 : Nginx stream modules
    pcp-pmda-nginx.x86_64 : Performance Co-Pilot (PCP) metrics for the Nginx Webserver
    
    # 查看软件包具体信息,重点是版本信息
    [root@localhost ~]# dnf info nginx
    Last metadata expiration check: 0:00:37 ago on Mon 20 Jul 2026 03:58:37 PM CST.
    Available Packages
    Name         : nginx
    Epoch        : 2
    Version      : 1.20.1
    Release      : 28.el9_8.2.rocky.0.1
    Architecture : x86_64
    Size         : 37 k
    Source       : nginx-1.20.1-28.el9_8.2.rocky.0.1.src.rpm
    Repository   : appstream
    Summary      : A high performance web server and reverse proxy server
    URL          : https://nginx.org
    License      : BSD
    Description  : Nginx is a web server and a reverse proxy server for HTTP, SMTP, POP3 and
                 : IMAP protocols, with a strong focus on high concurrency, performance and low
                 : memory usage.
    
    # 通过配置文件路径反查软件包名称 
    [root@localhost ~]# dnf provides /etc/ssh/sshd_config
    Last metadata expiration check: 0:03:58 ago on Mon 20 Jul 2026 03:58:37 PM CST.
    openssh-server-8.7p1-46.el9.rocky.0.1.x86_64 : An open source SSH server daemon
    Repo        : @System
    Matched from:
    Filename    : /etc/ssh/sshd_config
    
    openssh-server-9.9p1-7.el9_8.rocky.0.1.x86_64 : An open source SSH server daemon
    Repo        : baseos
    Matched from:
    Filename    : /etc/ssh/sshd_config

    查看已经安装的包

    # 查看所有可用包(数量巨大,建议配合grep)
    dnf list | head -20          # 只看前20行
    dnf list | grep mysql     # 只看MySQL相关的包
    
    # 查看已经安装的包
    dnf list installed | head -20

    安装软件包

    # 安装nginx(-y表示自动确认所有提示)
    dnf install -y nginx
    
    # 安装过程中的输出解读:
    # Dependencies resolved.  → 依赖关系已解决
    # Package    Architecture  Version  Repository  Size
    # Installing:  → 开始安装
    # Complete!  → 安装完成
    # 重点留意依赖部分
    [root@localhost ~]# dnf install nginx
    Last metadata expiration check: 0:11:42 ago on Mon 20 Jul 2026 03:58:37 PM CST.
    Dependencies resolved.
    ====================================================================================================================================================
     Package                              Architecture              Version                                          Repository                    Size
    ====================================================================================================================================================
    Installing:
     nginx                                x86_64                    2:1.20.1-28.el9_8.2.rocky.0.1                    appstream                     37 k
    Installing dependencies:
     nginx-core                           x86_64                    2:1.20.1-28.el9_8.2.rocky.0.1                    appstream                    568 k
     nginx-filesystem                     noarch                    2:1.20.1-28.el9_8.2.rocky.0.1                    appstream                     11 k
     rocky-logos-httpd                    noarch                    90.17-1.el9                                      appstream                     24 k
    
    Transaction Summary
    ====================================================================================================================================================
    Install  4 Packages
    
    Total download size: 639 k
    Installed size: 1.8 M
    Is this ok [y/N]: y
    Downloading Packages:
    (1/4): nginx-filesystem-1.20.1-28.el9_8.2.rocky.0.1.noarch.rpm                                                       31 kB/s |  11 kB     00:00
    (2/4): nginx-1.20.1-28.el9_8.2.rocky.0.1.x86_64.rpm                                                                  81 kB/s |  37 kB     00:00
    (3/4): rocky-logos-httpd-90.17-1.el9.noarch.rpm                                                                     139 kB/s |  24 kB     00:00
    
    (4/4): nginx-core-1.20.1-28.el9_8.2.rocky.0.1.x86_64.rpm                                                            670 kB/s | 568 kB     00:00
    
    ----------------------------------------------------------------------------------------------------------------------------------------------------
    Total                                                                                                               378 kB/s | 639 kB     00:01
    Running transaction check
    Transaction check succeeded.
    Running transaction test
    Transaction test succeeded.
    Running transaction
      Preparing        :                                                                                                                            1/1
      Running scriptlet: nginx-filesystem-2:1.20.1-28.el9_8.2.rocky.0.1.noarch                                                                      1/4
      Installing       : nginx-filesystem-2:1.20.1-28.el9_8.2.rocky.0.1.noarch                                                                      1/4
      Installing       : nginx-core-2:1.20.1-28.el9_8.2.rocky.0.1.x86_64                                                                            2/4
      Installing       : rocky-logos-httpd-90.17-1.el9.noarch                                                                                       3/4
      Installing       : nginx-2:1.20.1-28.el9_8.2.rocky.0.1.x86_64                                                                                 4/4
      Running scriptlet: nginx-2:1.20.1-28.el9_8.2.rocky.0.1.x86_64                                                                                 4/4
      Verifying        : nginx-2:1.20.1-28.el9_8.2.rocky.0.1.x86_64                                                                                 1/4
      Verifying        : nginx-core-2:1.20.1-28.el9_8.2.rocky.0.1.x86_64                                                                            2/4
      Verifying        : nginx-filesystem-2:1.20.1-28.el9_8.2.rocky.0.1.noarch                                                                      3/4
      Verifying        : rocky-logos-httpd-90.17-1.el9.noarch                                                                                       4/4
    
    Installed:
      nginx-2:1.20.1-28.el9_8.2.rocky.0.1.x86_64 nginx-core-2:1.20.1-28.el9_8.2.rocky.0.1.x86_64 nginx-filesystem-2:1.20.1-28.el9_8.2.rocky.0.1.noarch
      rocky-logos-httpd-90.17-1.el9.noarch
    
    Complete!

    安装多个软件和重新软件

    # 同时安装多个包,空格分隔
    dnf install -y vim wget curl tree
    
    # 重新安装软件
    dnf reinstall nginx

    ==离线安装==

    # 在线情况下先下载所有软件包及其依赖
    # 必须增加--resolve参数,否则,仅下载nginx主包,依赖包不会下载,断网环境还是无法安装
    dnf download nginx --resolve --destdir=./nginx
    
    # 断网环境下安装,可使用nmcli conn down ens160断网
    dnf install -y ./nginx/*

    几乎用不到,不用看,遇到了再说,一般都联网

    更新软件包

    # 更新单个软件到最新版本
    dnf update nginx
    
    # 更新所有软件到最新版本(生产环境慎用,容易裂开)
    dnf update

    image-20260724200717357


    卸载软件包

    # 卸载nginx(会同时删除依赖它的包,仅针对通过依赖自动安装的,手动安装的不算依赖)
    dnf remove nginx   
    # 模拟卸载(看会删什么,但实际不执行)
    dnf remove --assumeno nginx
    [root@localhost ~]# dnf remove nginx --assumeno
    Dependencies resolved.
    ====================================================================================================================================================
     Package                             Architecture              Version                                          Repository                     Size
    ====================================================================================================================================================
    Removing:
     nginx                               x86_64                    2:1.20.1-28.el9_8.2.rocky.0.1                    @appstream                    147 k
    Removing unused dependencies:
     nginx-core                          x86_64                    2:1.20.1-28.el9_8.2.rocky.0.1                    @appstream                    1.6 M
     nginx-filesystem                    noarch                    2:1.20.1-28.el9_8.2.rocky.0.1                    @appstream                    141
    
    Transaction Summary
    ====================================================================================================================================================
    Remove  3 Packages
    
    Freed space: 1.7 M
    Operation aborted.
    
    # 卸载后清理不再需要的依赖(生产环境慎用,容易裂开)
    dnf autoremove 
    

    讲解: image-20260724201438498

    历史记录

    [root@localhost ~]# dnf history
    
    ID     | Command line                                                                                  | Date and time    | Action(s)      | Altered
    
    ----------------------------------------------------------------------------------------------------------------------------------------------------
        12 | install nginx                                                                                 | 2026-07-20 16:43 | Install        |    3
        11 | remove nginx-core nginx-filesystem                                                            | 2026-07-20 16:42 | Removed        |    2
        10 | remove git                                                                                    | 2026-07-20 16:41 | Removed        |    2
         9 | remove nginx                                                                                  | 2026-07-20 16:41 | Removed        |    1
         8 | install ./git/git-2.52.0-1.el9.x86_64.rpm ./git/git-core-2.52.0-1.el9.x86_64.rpm ./git/git-co | 2026-07-20 16:28 | Install        |   65
         7 | install -y ./nginx/nginx-1.20.1-28.el9_8.2.rocky.0.1.x86_64.rpm ./nginx/nginx-core-1.20.1-28. | 2026-07-20 16:23 | Install        |    3
    
    # 查看某次操作的详细信息
    dnf history info 12
    
    # 撤销某次操操作
    dnf history undo 12

    group

    [root@localhost ~]# dnf grouplist
    Last metadata expiration check: 0:06:14 ago on Mon 20 Jul 2026 05:09:17 PM CST.
    Available Environment Groups:
       Server with GUI
       Server
       Workstation
       KDE Plasma Workspaces
       Custom Operating System
       Virtualization Host
    Installed Environment Groups:
       Minimal Install
    Available Groups:
       Fedora Packager
       VideoLAN Client
       Xfce
       Legacy UNIX Compatibility
       Console Internet Tools
       Container Management
       Development Tools
       .NET Development
       Graphical Administration Tools
       Headless Management
       Network Servers
       RPM Development Tools
       Scientific Support
       Security Tools
       Smart Card Support
       System Tools
    
    
    dnf groupinstall "Development Tools"  # --assumeno 可以使用此参数看看能安装哪些

    ==注意==:用不到不用记,平时用服务器,一定是用到什么装什么软件,不用装很多

    ==总结==:

    image-20260724210652717

    image-20260724210802972

    ==注意==:这是全部开发工具


    yum源管理

    软件仓库(Repository)
    ├── 本质:一个存放了大量RPM包和元数据的网络服务器
    ├── dnf的工作流程:
    │   └── 1. 读取 /etc/yum.repos.d/ 下的 .repo 配置文件
    │   └── 2. 连接仓库服务器,下载包,元数据(有哪些包、版本、依赖)
    │   └── 3. 本地缓存元数据到 /var/cache/dnf/
    │   └── 4. 根据用户命令查找、解析依赖、下载安装
    └── 默认仓库
    
    
        ├── BaseOS → 核心系统包(内核、glibc等)
        ├── AppStream → 应用软件包(nginx、httpd等)
        └── Extras → 额外包(非核心但有用)

    image-20260724220852265

    image-20260724220941393

    查看当前仓库信息

    # 查看已启用的仓库列表
    dnf repolist
    
    # 输出示例:
    # repo id            repo name
    # appstream          Rocky Linux 9 - AppStream
    # baseos             Rocky Linux 9 - BaseOS
    # extras             Rocky Linux 9 - Extras
    
    # 查看仓库配置文件位置
    ls -l /etc/yum.repos.d/
    -rw-r--r--. 1 root root 1627 Jul 20 10:00 rocky.repo
    -rw-r--r--. 1 root root  636 Jul 20 10:00 rocky-addons.repo
    
    # 查看某个仓库文件的内容
    cat /etc/yum.repos.d/rocky.repo

    *.repo文件格式**

    [baseos]                          # 仓库ID(唯一标识)
    name=Rocky Linux 9 - BaseOS      # 仓库名称(给人看的)
    baseurl=http://mirror.rocky...   # 软件包的实际下载地址
    mirrorlist=https://mirrors...    # 镜像列表(与baseurl二选一)
    enabled=1                         # 1=启用,0=禁用
    gpgcheck=1                        # 1=校验签名,0=不校验
    gpgkey=file:///etc/pki/rpm-gpg/RPM-GPG-KEY-Rocky-9  # 签名公钥

    image-20260724222315665

    image-20260724222701804

    ==实现==:

    image-20260724224719869

    换源——让速度更快

    # 创建备份目录
    mkdir -p /root/repo_backup
    
    # 备份所有repo文件
    cp /etc/yum.repos.d/*.repo /root/repo_backup/
    
    # 使用sed命令批量替换
    sed -e 's|^mirrorlist=|#mirrorlist=|g' 
        -e 's|^#baseurl=http://dl.rockylinux.org/$contentdir|baseurl=https://mirrors.ustc.edu.cn/rocky|g' 
        -i.bak /etc/yum.repos.d/rocky*.repo
    
    # 重建缓存
    dnf makecache

    ==注意==:具体可以用中科大的镜像源Rockylinux的软件库,这样下载速度就快点,一般换不换都差不多其实,可以看科大镜像源的网站看方法


    image-20260726231802914

    image-20260726231818337

    实现:

    image-20260724232049725

    image-20260724232800190

    image-20260724232821163

    添加epel

    官方软件源里的包数量相对有限,版本也偏旧,主要包含经过严格测试的核心软件,EPEL 的出现就是为了填补这个空白。它由 Fedora 社区维护,提供的软件包大多来自 Fedora 仓库,质量有保障,并且与 RHEL 系统兼容,不会与官方源里的包发生冲突或覆盖。这让系统管理员既能获得系统的稳定性,又能用 yum 或 dnf 命令方便地安装 Nginx、htop、ImageMagick 等常用工具

    # 安装epel-release包(自动配置好EPEL仓库)
    dnf install -y epel-release
    
    # 查看添加后的仓库
    dnf repolist
    
    # 现在可以安装EPEL专属的软件了
    dnf install -y htop
    
    htop #更帅的TUI

    image-20260724233702663

    htop更好用

    image-20260724233917216

    编译安装

    思考题:生产环境中,运维接到需求”必须在服务器上部署Nginx 1.25.x版本,且必须开启HTTP/3支持”。但官方仓库只有1.20版本,没有HTTP/3功能。怎么办?Support for QUIC and HTTP/3

    或者仓库中仅有pthon3.14.5,我想用3.14.6,甚至我想用prerelease的版本,怎么办?

    img

    解决方案:

    ​ 1. 等,等6-12个月,等着新的版本发布后,使用dnf update xxx

    ​ 2. 找这个软件官方提供的repo,比如nginx的nginx: Linux packages

    ​ 3. 找源代码,自己编译一份二进制可执行文件

    什么时候必须用源码编译?

    场景说明示例
    需要新版特性官方仓库版本太老需要python预发布,但仓库只有最新稳定版
    需要定制功能官方包默认不开启某些特性需要开启 –with-http_v3_module
    安全审计要求需要用特定补丁版本安全团队指定CVE补丁版本

    编译环境准备

    编译环境准备,其实完全可以粗略的理解为,此源代码开发环境的准备,所有的源代码运行环境和依赖都要准备好,才能进入编译环节。

    工具作用
    gccC语言编译器
    g++C++语言编译器
    make自动化构建工具

    以上c语言编译经常遇到的,了解即可。

    一般c项目的编译流程

    源码编译"三步走"战略:
    
    ┌─────────────┐     ┌─────────────┐     ┌─────────────┐
    │ ./configure │ ──▶ │    make     │ ──▶│ make install│
    └─────────────┘     └─────────────┘     └─────────────┘
          ▲                   ▲                   ▲
          │                   │                   │
       检查环境(配置功能)      编译代码            安装到系统
        生成Makefile         生成可执行文件          指定路径放置

    image-20260725085625609

    ==总结==:

    image-20260725090145440

    image-20260725114332588

    编译代码雨

    cmatrix-2.0.tar.gz

    GitHub – abishekvashok/cmatrix: Terminal based “The Matrix” like implementation · GitHub

    mkdir cmatrix
    tar xvf cmatrix-2.0.tar.gz -C ./cmatrix
    cd cmatrix/cmatrix-2.0
    dnf install gcc make autoconf ncurses-devel automake
    autoreconf -i
    ./configure  # 检查环境并生成Makefile供make使用
    make -j 4 #使用4个核心并行编译
    # 如果正常,此时将获得cmatrix二进制文件,./cmatrix便可以运行了
    make clean # 可以清除make产生的中间文件

    image-20260726212806196

    image-20260726212828644

    image-20260726212852299


    编译小火车

    sl-5.02.tar.gz

    GitHub – mtoyoda/sl: SL(1): Cure your bad habit of mistyping · GitHub

    # 进入源代码目录,直接make即可
    [root@localhost sl-5.02]# ls
    LICENSE  Makefile  README.ja.md  README.md   sl.1  sl.1.ja  sl.c  sl.h
    
    [root@localhost sl-5.02]# make
    gcc -O -o sl sl.c -lncurses
    
    [root@localhost sl-5.02]# ./sl

    编译python(拓展部分,学有余力可尝试)

    Download Python | Python.org 从此网站下载python源代码

    sudo dnf install 
          gcc gcc-c++ gdb lzma glibc-devel libstdc++-devel openssl-devel 
          readline-devel zlib-devel libzstd-devel libffi-devel bzip2-devel 
          xz-devel sqlite sqlite-devel sqlite-libs libuuid-devel gdbm-libs 
          perf expat expat-devel mpdecimal python3-pip
    
    cd /root/Python-3.15.0b4
    ./configure # 不加参数,默认配置就行
    make -j 8   # 8核心情况下,大概1分钟左右
    ls -al python  # 便可以获得python二进制
    [root@localhost Python-3.15.0b4]# ./python  # 一个repo中不存在的python我们就得到了
    Python 3.15.0b4 (main, Jul 20 2026, 19:21:56) [GCC 11.5.0 20240719 (Red Hat 11.5.0-14)] on linux
    Type "help", "copyright", "credits" or "license" for more information.
    >>>

    二进制文件与软件包管理

    image-20260726204108920

    image-20260726204124080

    image-20260726204141064

    ==稳定与研发新特性==:

    image-20260726234921757

    image-20260726234935967