2.2 配置文件与系统设置
预计阅读时间:28 分钟
📖 目录
学习目标
学完本章后,你将能够:
- 理解 Linux 配置文件体系的组织方式(
/etc结构) - 查看和修改系统配置(主机名、时区、语言、网络)
- 使用
sysctl查看和修改内核运行时参数 - 理解
sysctl.conf和/etc/sysctl.d/的配置机制 - 通过
hostnamectl、timedatectl、localectl管理系统设置 - 理解用户级配置(
~/.bashrc、~/.profile)与系统级配置的分工 - 查看、设置、导出环境变量,理解
$PATH的工作原理并自定义 PATH - 理解配置文件修改的最佳实践(备份、语法检查、原子写入)
核心知识
- /etc——系统的配置目录,几乎所有系统级配置都在这里
- sysctl——运行时修改内核参数的接口,部分参数可在
/etc/sysctl.conf中持久化 - hostnamectl——查看和修改系统主机名的 systemd 工具
- timedatectl——查看和设置系统时间、时区、NTP 同步的 systemd 工具
- localectl——查看和设置系统语言、键盘布局的 systemd 工具
- 内核参数(Kernel Parameters)——控制内核行为的可调变量,分布在
/proc/sys/目录树中 - /etc/default/grub——GRUB 引导加载程序的配置文件
- ~/.bashrc——用户级 Shell 配置文件(non-login shell 加载),定义别名、提示符和变量
- 环境变量——影响程序行为的全局键值对配置,通过
export提升为子进程可继承 - $PATH——环境变量中最重要的一员,Shell 按它列出的目录顺序搜索可执行文件
知识关联
- 前置知识:1.5:文件系统结构 的文件系统结构(/etc 的定位);1.7:用户与权限管理 的用户账户(
/etc/passwd、/etc/shadow)是 /etc 配置文件的例子;1.8:软件包管理 的软件源配置也在 /etc 下;1.9:重定向与管道 的管道与重定向(echo x | sudo tee的写法) - 后续影响:3.3:实战:搭建个人网站(服务管理)的 systemd 单元配置、3.4:Nginx Web服务器(安全)的 sysctl 安全参数都依赖本章基础;2.1:Shell 脚本入门 Shell 脚本中
${VAR:-default}默认值语法在环境变量一节直接使用 - 配套技术:配置文件编辑用 1.6:文件查看与文本编辑 的 Vim/Nano;修改后需要 3.3:实战:搭建个人网站 的 systemctl 重启服务;2.3:系统信息与性能查看 的系统信息查看可辅助验证配置效果
- 在整个体系中的位置:配置文件是连接"用户意图"和"系统行为"的桥梁。学会管理配置是系统管理的中阶技能
原理讲解
这是 Unix/Linux 哲学的核心设计之一:"配置即文本"。原因有四:① 可移植性——任何文本编辑器(nano、vim、甚至 echo)都能修改配置,不依赖特定 GUI 工具;② 可审计——用 diff 对比修改前后的配置文件,一眼看出改了什么;③ 可恢复——配置改坏了,备份文件拷回来就行,不需要"卸载重装";④ 可自动化——Shell 脚本可以 sed 批量修改配置,Ansible 等工具可以远程推送配置文件。Windows 的注册表(二进制数据库)需要专用工具才能编辑和恢复,而 Linux 的 /etc/ssh/sshd_config 就是一个普通文本文件——这使得自动化运维成为可能。
sysctl -w net.ipv4.ip_forward=1 的底层过程:① sysctl 读取参数名 net.ipv4.ip_forward,将其转换为路径 /proc/sys/net/ipv4/ip_forward(点变斜杠);② 用 open() 系统调用打开该文件;③ 用 write() 写入值 1;④ 内核中注册了该虚拟文件的 proc_handler,在 write 时触发回调函数,将值更新到内核数据结构中。所以 sysctl -w 和 echo 1 > /proc/sys/xxx 本质完全相同——都是通过虚拟文件系统的 write 操作触发内核回调。这也解释了为什么 /proc/sys/ 下的文件大小显示为 0——它们不占用磁盘,是内核动态生成的"窗口"。
hostnamectl set-hostname new-name 比 echo "new-name" > /etc/hostname 多做了三件事:① 同步更新内核的 hostname(通过 sethostname() 系统调用,立即生效无需重启);② 更新 /etc/hosts 中对应的 127.0.1.1 映射;③ 触发 systemd 的 D-Bus 通知,让相关服务感知变化。timedatectl set-timezone 同理——它不仅改 /etc/timezone,还更新 /etc/localtime 符号链接并通知正在运行的服务。直接编辑文件只能做到一半的事,systemd 工具保证了"改了就生效"。
1. /etc——Linux 配置文件的"神经中枢"
/etc(et cetera 的缩写)是 Linux 系统配置的集中存放地。几乎所有系统级软件都将配置文件放在这个目录或其子目录下。
$ ls /etc
# 核心系统配置
/etc/passwd # 用户账户
/etc/shadow # 密码哈希
/etc/group # 用户组
/etc/sudoers # sudo 权限
/etc/fstab # 文件系统挂载表
# 网络配置
/etc/hostname # 主机名
/etc/hosts # 本地 DNS 映射
/etc/resolv.conf # DNS 服务器
/etc/network/ # 网络接口配置(传统,已废弃,推荐 Netplan 或 systemd-networkd)
/etc/netplan/ # Ubuntu 网络配置(新版)
# 软件源
/etc/apt/sources.list # APT 软件源
/etc/apt/sources.list.d/ # 额外软件源
# SSH
/etc/ssh/sshd_config # SSH 服务端配置
/etc/ssh/ssh_config # SSH 客户端配置
# 安全
/etc/security/limits.conf # 资源限制
/etc/login.defs # 登录策略
# 时间
/etc/chrony/chrony.conf # NTP 客户端配置
/etc/timezone # 时区
/etc/localtime # 时区文件(符号链接)
# 内核
/etc/sysctl.conf # 内核参数持久化
/etc/sysctl.d/ # 内核参数分片
systemctl(如 sudo systemctl restart nginx),不要使用已废弃的 service 命令(如 sudo service nginx restart)。同样,查看网络配置请使用 ip addr,不要使用已废弃的 ifconfig。2. hostname——系统的主机名
# 查看主机名
hostname
# 输出: ubuntu-pc
hostnamectl # 更详细的信息
# 输出: Static hostname: ubuntu-pc
# 输出: Icon name: computer-vm
# 输出: Operating System: Ubuntu 24.04 LTS
# 修改主机名(推荐使用 hostnamectl)
sudo hostnamectl set-hostname my-server
# 修改主机名的三种方式:
# 1. hostnamectl(推荐,systemd 工具)
sudo hostnamectl set-hostname new-hostname
# 2. 直接编辑文件
echo "new-hostname" | sudo tee /etc/hostname
# 输出: new-hostname
# 3. 临时修改(重启后失效)
sudo hostname new-hostname
# 主机名也需同步到 /etc/hosts
# 确保 127.0.1.1 指向你的新主机名
sudo sed -i 's/old-hostname/new-hostname/g' /etc/hosts
3. timedatectl——时间和时区
# 查看当前时间、时区、NTP 状态
timedatectl
# 输出: Local time: Thu 2026-07-30 10:30:00 CST
# 输出: Universal time: Thu 2026-07-30 02:30:00 UTC
# 输出: Time zone: Asia/Shanghai (CST, +0800)
# 输出: NTP enabled: yes
# 列出所有可用时区
timedatectl list-timezones | grep Shanghai
# 输出: Asia/Shanghai
timedatectl list-timezones | grep -E "Europe/(Amsterdam|Berlin)"
# 输出: Europe/Amsterdam
# 输出: Europe/Berlin
# 设置时区
sudo timedatectl set-timezone Asia/Shanghai
sudo timedatectl set-timezone Europe/Amsterdam
# 启用 NTP 时间同步
sudo timedatectl set-ntp true
# 手动设置时间(需要先关闭 NTP)
sudo timedatectl set-ntp false
sudo timedatectl set-time "2026-12-25 08:30:00"
sudo timedatectl set-ntp true # 再启用 NTP
4. localectl——语言和键盘布局
# 查看当前语言和键盘设置
localectl
# 输出: System Locale: LANG=en_US.UTF-8
# 输出: VC Keymap: us
# 列出所有可用的语言环境
locale -a
# 输出: C
# 输出: en_US.utf8
# 输出: zh_CN.utf8
# 设置系统语言
sudo localectl set-locale LANG=zh_CN.UTF-8
sudo localectl set-locale LANG=en_US.UTF-8
# 设置键盘布局
sudo localectl set-keymap us
sudo localectl set-keymap fr
# 生成语言环境(如果某个 locale 不可用)
sudo locale-gen zh_CN.UTF-8
# 输出: Generating locales... zh_CN.UTF-8... done
5. sysctl——内核运行时参数
Linux 内核有数百个运行时参数,它们在 /proc/sys/ 目录树中以文件形式呈现。你可以通过 sysctl 命令或直接写这些文件来修改内核行为。
# 查看所有可调内核参数
sysctl -a | head -20
# 输出: dev.cdrom.autoclose = 1
# 输出: fs.file-max = 100000
# 输出: kernel.hostname = ubuntu-pc
# 查看特定参数
sysctl net.ipv4.ip_forward # IP 转发
# 输出: net.ipv4.ip_forward = 0
sysctl kernel.hostname # 主机名(内核视角)
# 输出: kernel.hostname = ubuntu-pc
sysctl vm.swappiness # 内存交换倾向(0-100)
# 输出: vm.swappiness = 60
sysctl fs.file-max # 系统最大文件句柄数
# 输出: fs.file-max = 100000
# 临时修改参数
sudo sysctl -w net.ipv4.ip_forward=1
# 输出: net.ipv4.ip_forward = 1
sudo sysctl -w vm.swappiness=10
# 输出: vm.swappiness = 10
sudo sysctl -w fs.file-max=100000
# 输出: fs.file-max = 100000
# 等价于直接写 /proc/sys/
echo 1 | sudo tee /proc/sys/net/ipv4/ip_forward
# 输出: 1
# 注意 /proc/sys/ 中的路径用点代替斜杠:
# net/ipv4/ip_forward = net.ipv4.ip_forward
# 持久化修改(写入配置文件)
echo 'net.ipv4.ip_forward = 1' | sudo tee -a /etc/sysctl.conf
# 输出: net.ipv4.ip_forward = 1
# 或放在分片目录中
echo 'vm.swappiness = 10' | sudo tee /etc/sysctl.d/99-swap.conf
# 输出: vm.swappiness = 10
# 重新加载所有 sysctl 配置
sudo sysctl --system
# 输出: * Applying /etc/sysctl.d/99-swap.conf ...
# 输出: * Applying /etc/sysctl.conf ...
# 或 sysctl -p(仅加载 /etc/sysctl.conf)
| 常用 sysctl 参数 | 含义 | 推荐值 |
|---|---|---|
net.ipv4.ip_forward | IP 转发(路由/网关功能) | 0(默认),1(如果作为路由器) |
net.ipv4.tcp_syncookies | SYN Flood 防护 | 1(默认) |
vm.swappiness | 系统使用 swap 的倾向(越低越少用) | 10(服务器),60(桌面默认) |
fs.file-max | 系统级最大打开文件数 | 取决于内存,通常 100000+ |
net.core.somaxconn | 最大 TCP 连接等待队列 | 1024-65535(高并发服务器) |
kernel.pid_max | 最大 PID 数 | 4194304(64 位默认),大服务器可调高 |
网络参数实战——高并发 Web 服务器的典型调优:当一台服务器要支撑大量短连接(如 Nginx 反代、API 网关),默认参数往往不够用。下面是一组经过验证的典型配置:
# 高并发短连接场景的 TCP 调优(写入 /etc/sysctl.d/98-tcp.conf)
# 1. 允许 TIME_WAIT 状态下的端口快速复用
net.ipv4.tcp_tw_reuse = 1
# 2. 主动关闭方 FIN_WAIT_2 超时(默认 60 秒;注意这与 TIME_WAIT 无关)
net.ipv4.tcp_fin_timeout = 15
# 3. 增大 SYN 半连接队列(防 SYN Flood 丢连接)
net.ipv4.tcp_max_syn_backlog = 8192
net.core.somaxconn = 65535
# 4. 增大 TCP 读写缓冲区(高带宽长连接场景)
net.core.rmem_max = 16777216
net.core.wmem_max = 16777216
# 5. 允许本地端口范围(默认 32768-60999,放开后可支持更多并发连接)
net.ipv4.ip_local_port_range = 1024 65535
# 6. tcp_tw_recycle 已在 4.12 内核移除(写了无效)
# net.ipv4.tcp_tw_recycle = 1 ← 不要写!4.12 已移除
# 应用后验证
sudo sysctl --system
sysctl net.ipv4.tcp_fin_timeout
# 输出: net.ipv4.tcp_fin_timeout = 15
ss -s | head -5
# 输出: Total: 1234 (kernel 4567)
# 输出: TCP: 789 (estab 321, closed 456, orphaned 12, synrecv 0, timewait 234)
# timewait 明显下降说明 tcp_tw_reuse 生效
tcp_tw_recycle 在 4.12 内核已被移除(它会导致 NAT 环境丢包),很多老教程还在推荐它。修改内核参数前先 man 7 tcp 或查询内核文档确认参数仍存在,并在测试环境验证。6. 配置文件的编辑和安全管理
编辑配置文件的核心规范:
# 1. 备份原文件
sudo cp /etc/ssh/sshd_config /etc/ssh/sshd_config.bak.$(date +%Y%m%d)
# 2. 编辑
sudo vim /etc/ssh/sshd_config
# 3. 语法检查(如果工具支持)
sudo sshd -t # 检查 sshd 配置文件语法
sudo nginx -t # 检查 nginx 配置语法
# 输出: nginx: the configuration file /etc/nginx/nginx.conf syntax is ok
# 输出: nginx: configuration file /etc/nginx/nginx.conf test is successful
sudo apachectl configtest # 检查 Apache 配置语法
# 输出: Syntax OK
# 4. 重启服务使配置生效
sudo systemctl restart sshd
# 5. 如果修改导致无法连接,保留当前终端(别关!),
# 用另一个终端测试。修复或恢复备份
sudo cp /etc/ssh/sshd_config.bak.20260730 /etc/ssh/sshd_config
sudo systemctl restart sshd
7. 分片配置目录——/etc/xxx.d/ 机制
现代 Linux 发行版很少让你直接修改某个大配置文件,而是鼓励在 /etc/xxx.d/ 分片目录中放自己的小配置文件。这样做的好处:软件包升级时不会覆盖你的自定义配置,每个软件包可以各自管理自己的片段,删除一个文件就等于"删除一项配置"。
# 常见的分片配置目录
ls /etc/*.d/ | head -20
# 输出: /etc/apt/sources.list.d/ 软件源片段
# 输出: /etc/sysctl.d/ 内核参数片段
# 输出: /etc/rsyslog.d/ 日志规则片段
# 输出: /etc/logrotate.d/ 日志轮转规则片段
# 输出: /etc/profile.d/ 登录环境变量片段
# 输出: /etc/network/if-up.d/ 网络接口启用时执行的脚本
# 输出: /etc/systemd/system/ systemd 单元覆盖片段
# 加载顺序规则:按文件名字母序,后加载的覆盖先加载的
ls -1 /etc/sysctl.d/
# 输出: 10-network-security.conf # 数字前缀控制顺序
# 输出: 50-default.conf
# 输出: 99-swap.conf # 99 = 最后加载,优先级最高
# 实例:在分片目录中添加内核参数(比改 sysctl.conf 更规范)
echo 'net.core.somaxconn = 65535' | sudo tee /etc/sysctl.d/98-tcp.conf
sudo sysctl --system
| 分片目录 | 控制什么 | 你的配置文件放哪 |
|---|---|---|
/etc/sysctl.d/ | 内核运行时参数 | /etc/sysctl.d/99-my.conf(99 保证最后加载) |
/etc/apt/sources.list.d/ | APT 软件源 | /etc/apt/sources.list.d/mirror.list(需以 .list 结尾) |
/etc/profile.d/ | 登录 Shell 的环境变量 | /etc/profile.d/mylang.sh(需以 .sh 结尾且可执行) |
/etc/logrotate.d/ | 日志轮转策略 | /etc/logrotate.d/myapp(无需扩展名) |
/etc/systemd/system/ | systemd 单元覆盖与自定义服务 | /etc/systemd/system/myapp.service |
/etc/sysctl.conf)通常由发行版维护,软件包升级可能覆盖。把自定义内容放到 /etc/xxx.d/ 中,升级无忧,且 ls /etc/xxx.d/ 一眼就能看到你改了什么。8. 配置审计——改了什么、什么时候改的
生产环境最常见的追责问题是"这个配置文件谁改的、为什么改"。工具 etckeeper 用 Git 跟踪 /etc 下的所有变化(需 sudo apt install etckeeper),每次 apt 安装软件包后自动提交一次快照。
# 初始化 etckeeper(安装后通常已自动初始化)
sudo etckeeper init
sudo etckeeper commit "initial commit"
# 每次 apt 操作后自动 commit(etckeeper 集成在 apt 钩子中)
# 手动提交配置修改
sudo etckeeper commit "tune sysctl for high concurrency"
# 查看配置历史
sudo etckeeper vcs log --oneline | head -10
# 输出: abc1234 tune sysctl for high concurrency
# 输出: 9f8e7d6 update package lists
# 输出: ...
# 查看某个文件的历史版本
sudo etckeeper vcs log -p -- /etc/sysctl.conf | head -40
# 回滚到上一个版本
sudo etckeeper vcs checkout HEAD~1 -- /etc/sysctl.conf
sudo sysctl --system # 别忘了重新加载
# 没有 etckeeper 时的朴素做法:定期快照
sudo tar czf /root/etc-backup-$(date +%Y%m%d).tar.gz /etc
审查配置修改的通用流程:diff 对比备份、etckeeper vcs log 查看历史、systemctl status 确认服务状态。这三个动作组合起来,90% 的"配置怎么突然不生效了"问题都能快速定位。
9. update-alternatives——系统默认工具管理
当系统同时安装了多个功能类似的软件(如 Vim 和 Nano、Python 3.8 和 3.11),update-alternatives 通过符号链接统一管理"谁是指定默认工具"。
# 查看当前默认编辑器
update-alternatives --list editor
# 输出: /bin/ed
# 输出: /bin/nano
# 输出: /usr/bin/vim.basic
update-alternatives --display editor | head -5
# 输出: editor - auto mode
# 输出: link currently points to /usr/bin/vim.basic
# 交互式切换默认编辑器
sudo update-alternatives --config editor
# 输出: There are 3 choices for the alternative editor (providing /usr/bin/editor).
# 输出: 0 /usr/bin/vim.basic 30 auto mode
# 输出: 1 /bin/ed -100 manual mode
# 输出: 2 /bin/nano 40 manual mode
# 输出: 3 /usr/bin/vim.basic 30 manual mode
# 输入数字后回车,/usr/bin/editor 符号链接即切换
# 非交互式设置
sudo update-alternatives --set editor /bin/nano
# 注册新的 alternative(--install 链接 名称 路径 优先级)
sudo update-alternatives --install /usr/bin/editor editor /usr/bin/micro 50
# 其他常见 alternative:python、java、awk、x-terminal-emulator
update-alternatives --list awk
# 输出: /usr/bin/mawk
# 输出: /usr/bin/gawk
10. 用户级配置——~/.bashrc 与 ~/.profile
前面讲的都是系统级配置(/etc 下,影响所有用户)。作为个人用户,你还有一份"私有配置":~/.bashrc 和 ~/.profile。Shell 在启动时按类型读取不同的配置文件:
Login Shell vs Non-login Shell:
- Login Shell:通过
ssh登录、su -、或 tty 登录时启动。读取:/etc/profile→~/.profile(或~/.bash_profile/~/.bash_login,按顺序第一个存在的) - Non-login Shell:在图形界面中打开终端时启动。读取:
~/.bashrc
# 判断当前 Shell 类型
echo $0 # -bash(login shell),bash(non-login)
shopt -q login_shell && echo "login shell" || echo "non-login"
# 推荐的最佳实践:在 ~/.bashrc 中写所有配置,
# 然后在 ~/.profile 中 source ~/.bashrc
# 这样无论什么 Shell 类型,配置都会加载
加载顺序(Bash):
# Login Shell(SSH / tty / su -)
/etc/profile # 系统级,对所有用户生效
├── /etc/bash.bashrc # 系统级 bash 配置
└── ~/.bash_profile # 用户级(只读第一个存在的)
├── ~/.bash_login
└── ~/.profile # 推荐使用
# Non-login Shell(图形终端)
~/.bashrc # 用户级 bash 配置
~/.bashrc 是你最常编辑的文件——别名、自定义 PATH、默认编辑器、提示符(PS1)都写在这里:
nano ~/.bashrc
# 典型的 ~/.bashrc 内容
# 别名——代替长命令
alias ll='ls -lah'
alias la='ls -A'
alias ..='cd ..'
alias ...='cd ../..'
alias gs='git status'
# PATH 自定义
export PATH=$PATH:$HOME/.local/bin
# 默认编辑器
export EDITOR=vim
# 自定义提示符(PS1)
# \u = 用户名,\h = 主机名,\w = 完整路径,\$ = $ 或 #
export PS1='\u@\h:\w\$ '
# 历史命令设置
export HISTSIZE=10000 # 内存中保留 10000 条
export HISTFILESIZE=20000 # 文件中保留 20000 条
export HISTCONTROL=ignoredups # 忽略连续重复的命令
# 让修改生效
source ~/.bashrc # 或 . ~/.bashrc
# 或者关闭终端重新打开
~/.bashrc,不要改 /etc/profile(影响所有用户,且会被软件包升级覆盖)。如果需要给所有用户加环境变量,用 /etc/profile.d/ 里的 .sh 文件(第 7 节分片机制的又一例)。11. 环境变量——查看、设置与持久化
环境变量是操作系统为每个进程维护的一组键值对,程序运行时通过查询它们来决策。查看方式:
# 查看所有环境变量
printenv
env
# 查看单个变量
echo $HOME # /home/alice
echo $USER # alice
echo $SHELL # /bin/bash
echo $LANG # zh_CN.UTF-8(语言和编码)
变量的作用范围——Shell 变量只在当前 Shell 有效,用 export 提升为环境变量后子进程才能继承:
# Shell 变量 vs 环境变量
MYVAR="hello" # Shell 变量(子进程看不到)
export MYENV="world" # 环境变量(子进程继承)
bash -c 'echo $MYVAR' # 空输出(子进程看不到 Shell 变量)
bash -c 'echo $MYENV' # 输出 "world"(子进程继承环境变量)
常用环境变量:
| 变量名 | 含义 | 典型值 |
|---|---|---|
PATH | 可执行文件搜索路径 | /usr/local/bin:/usr/bin:/bin |
HOME | 当前用户的家目录 | /home/alice |
USER / LOGNAME | 当前用户名 | alice |
SHELL | 当前 Shell 的路径 | /bin/bash |
LANG | 系统语言和编码 | zh_CN.UTF-8 或 en_US.UTF-8 |
PWD | 当前工作目录 | /home/alice/projects |
OLDPWD | 上一个工作目录(cd - 使用) | /tmp |
EDITOR | 默认文本编辑器 | vim 或 nano |
TERM | 终端类型 | xterm-256color |
PS1 | 主命令提示符格式 | \[\e[32m\]\u@\h:\w\$\[\e[0m\] |
DISPLAY | X11 显示服务器地址 | :0(本地)或 :10.0(远程) |
$PATH——最重要的环境变量:当你输入 ls 并回车,Shell 在 $PATH 列出的目录中依次搜索名为 ls 的可执行文件:
$ echo $PATH
/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
# 自定义 PATH(临时——当前 Shell 有效)
export PATH=$PATH:/home/alice/mybin
# 永久添加(写入 ~/.bashrc)
echo 'export PATH=$PATH:$HOME/mybin' >> ~/.bashrc
source ~/.bashrc
.(当前目录)放在 PATH 前面,攻击者可以在某个目录下放一个名为 ls 的恶意脚本,当你 cd 进去执行 ls 时就会中招。所以安全规范永远不要把 . 放在 PATH 中。设置与持久化方法汇总:
| 方法 | 作用范围 | 语法 |
|---|---|---|
export VAR="value" | 当前 Shell 及子进程 | 最常用的设置方式 |
VAR="value" command | 仅该命令 | 临时修改变量执行一次命令 |
unset VAR | 删除变量 | 移除变量 |
export VAR=$VAR:/new/path | 追加到已有变量 | PATH 追加常用 |
# 不同作用域的演示
# 方法 1:临时,仅单个命令
LANG=en_US.UTF-8 date
# 方法 2:当前 Shell
export MY_APP_MODE=development
python3 myapp.py # 可以通过 os.environ['MY_APP_MODE'] 读取
# 方法 3:持久化(写入配置文件)
echo 'export MY_APP_MODE=production' >> ~/.bashrc
source ~/.bashrc
# 方法 4:系统级(/etc/environment 或 /etc/profile.d/)
sudo nano /etc/environment
# MY_APP_MODE=staging
# 格式:每行 KEY=VALUE,不需要 export
12-factor 应用与 .env:现代应用开发(尤其是 Docker 和云原生)遵循"配置从环境变量注入"的原则(12-factor 的第 3 条)。本地开发通常用一个 .env 文件管理变量,运行时再加载:
# .env 文件内容(每行 KEY=VALUE,不加 export)
DATABASE_URL=postgres://app:pass@localhost:5432/app
REDIS_URL=redis://localhost:6379/0
LOG_LEVEL=info
# 手动加载 .env(不依赖额外工具)
set -a; source .env; set +a
# set -a 使后续赋值自动 export,set +a 关闭
# 验证
echo $DATABASE_URL
# 输出: postgres://app:pass@localhost:5432/app
.env 必须加入 .gitignore——它通常包含数据库密码和 API Key。工程上一般用 .env.example(只含键名和占位值)提交到仓库,真实 .env 由开发者各自创建。服务端环境(如 K8s)则用 Secret 注入,而不是把密钥写进环境变量文件提交。同理,API Key、数据库密码等也不应写在 ~/.bashrc(会出现在历史记录和进程列表中)。调试技巧:当程序行为诡异时,用 env 和 declare -p 检查实际生效的变量:
env | sort # 查看全部环境变量(排序便于阅读)
declare -p LANG PATH # 查看变量的类型和值
env | grep -i proxy # 排查代理相关配置
env -i bash -c 'echo $PATH' # 干净环境测试:脚本是否依赖外部变量
示例代码
# 练习 1:探索 /etc
ls /etc | head -20 # 前 20 个配置文件
# 输出: adduser.conf
# 输出: apt
# 输出: bash.bashrc
ls -d /etc/*.conf # 所有 .conf 文件
# 输出: /etc/adduser.conf /etc/debconf.conf /etc/resolv.conf
wc -l /etc/passwd /etc/group /etc/fstab # 这些文件的行数
# 输出: 42 /etc/passwd
# 输出: 58 /etc/group
# 输出: 13 /etc/fstab
# 练习 2:查看和修改主机名
hostnamectl
# 输出: Static hostname: ubuntu-pc
echo "我的主机名是: $(hostname)"
# 输出: 我的主机名是: ubuntu-pc
# 练习 3:检查和设置时区
timedatectl
# 输出: Local time: Thu 2026-07-30 10:30:00 CST
timedatectl list-timezones | grep -E "Shanghai|Tokyo|Amsterdam|London"
# 输出: Asia/Shanghai
# 输出: Asia/Tokyo
# 输出: Europe/Amsterdam
# 输出: Europe/London
# 练习 4:查看 sysctl 参数
sysctl vm.swappiness
# 输出: vm.swappiness = 60
sysctl net.ipv4.tcp_syncookies
# 输出: net.ipv4.tcp_syncookies = 1
sysctl fs.file-max
# 输出: fs.file-max = 100000
# 练习 5:临时修改内核参数(不需要重启)
# 注意:这些修改重启后消失
sudo sysctl -w vm.swappiness=30
# 输出: vm.swappiness = 30
sysctl vm.swappiness # 验证修改
# 输出: vm.swappiness = 30
# 练习 6:查看 /etc/sysctl.conf
cat /etc/sysctl.conf | grep -v "^#" | grep -v "^$" # 看非注释行
# 输出: net.ipv4.ip_forward=1
# 练习 7:环境变量基础
printenv | head -10 # 查看前 10 条环境变量
echo "家目录: $HOME,用户名: $USER" # 引用变量
TESTVAR="hello"
bash -c 'echo $TESTVAR' # 空!子进程看不到 Shell 变量
export TESTVAR
bash -c 'echo $TESTVAR' # 输出!export 后子进程继承
# 练习 8:PATH 自定义
echo $PATH # 当前 PATH
which myapp # command not found
export PATH=$PATH:$HOME/bin # 临时加入家目录 bin
# 永久生效:把 export 行写入 ~/.bashrc 后 source ~/.bashrc
# 练习 9:判断 Shell 类型与配置文件加载
echo $0 # -bash = login shell
shopt -q login_shell && echo "login shell" || echo "non-login"
ls -la ~/.bashrc ~/.profile # 两个用户配置文件是否存在
常见错误
| 错误/误区 | 解决方案 |
|---|---|
| "直接修改 /etc/resolv.conf 后重启被还原" | 现代 Ubuntu 使用 systemd-resolved 或 Netplan 管理 DNS。/etc/resolv.conf 是符号链接。应修改 /etc/systemd/resolved.conf 或使用 netplan 配置。 |
| "修改 /etc/sysctl.conf 后没生效" | 需要运行 sudo sysctl --system 或 sudo sysctl -p。纯文本修改不会自动触发内核重新加载。 |
| "编辑了 /etc/ssh/sshd_config 但忘了 restart" | 配置文件的修改必须重启对应的服务才能生效。sudo systemctl restart sshd。 |
| "语法错误导致服务无法启动" | 编辑前备份(cp file file.bak),编辑后测试语法(sshd -t),确认无误再重启。 |
| "用 sudo 误删了 /etc 下的文件" | 恢复策略:从另一台同版本系统的机器复制,或用 apt 重新安装包含该文件的软件包。例如 apt list --installed | grep passwd 找到包,apt reinstall passwd 恢复 /etc/passwd。 |
| "修改了 ~/.bashrc 但没效果" | 修改后需要 source ~/.bashrc 或重新打开终端。~/.bashrc 只在 Shell 启动时读取一次。 |
| "export VAR 写在了脚本里,但运行完脚本变量没生效" | 通过 ./script.sh 执行脚本会启动子 Shell。子 Shell 中 export 的变量不影响父 Shell。用 source script.sh 让变量在当前 Shell 生效。 |
| "在 ~/.bashrc 中写错了导致终端打不开" | 用完整路径调用编辑器:/usr/bin/nano ~/.bashrc(因为 PATH 可能也被破坏了)。或者 /bin/bash --no-rc 启动不加载配置的干净 Shell,修复后退出。 |
| "混淆了 /etc/profile 和 ~/.bashrc 的作用" | /etc/profile 对所有用户生效(需要 root 修改)。~/.bashrc 只对当前用户生效。你的个人配置始终放在 ~/.bashrc。 |
最佳实践
| # | 建议 | 说明 |
|---|---|---|
| 1 | 编辑配置文件前先备份 | cp file file.bak.$(date +%Y%m%d)。这个习惯在事故排障中往往直接决定恢复速度。 |
| 2 | 修改后先检查语法再重启服务 | sshd -t、nginx -t、apachectl configtest。大部分服务提供语法检查命令。 |
| 3 | 用 /etc/xxx.d/ 分片目录组织配置 | 相比修改单个大文件,在 /etc/sysctl.d/、/etc/apt/sources.list.d/ 中添加 .conf 文件更清晰,升级时不会被覆盖。 |
| 4 | 始终用 systemd 工具(timedatectl/localectl/hostnamectl) | 这些工具比直接编辑文件更安全——它们会同步相关配置、触发必要的通知。 |
| 5 | 用 diff 审查配置修改 | diff /etc/ssh/sshd_config.bak /etc/ssh/sshd_config 可以清清楚楚看到你改了什么。 |
| 6 | 个人配置写 ~/.bashrc,不写 /etc/profile | 避免影响系统上其他用户。全局配置使用 /etc/profile.d/ 中的 .sh 文件。 |
| 7 | PATH 用冒号追加,不要覆盖 | 写 export PATH=$PATH:/new/path 而非 export PATH=/new/path。后者会覆盖系统标准路径导致大量命令消失。 |
| 8 | 敏感变量不要写在 ~/.bashrc | API Key、数据库密码等不应放在 ~/.bashrc 或提交到仓库的 .env 中。使用专门的配置管理或 Secret 机制。 |
练习题
- (概念)在
/etc目录中找到至少 5 个你在之前章节中实际使用过的配置文件。 - (概念)sysctl 修改(
sysctl -w)和直接写/proc/sys/文件有什么区别? - (实操)使用
timedatectl查看你的系统当前时区和 NTP 状态。如果你不在上海时区,修改为你的本地时区。 - (实操)使用
hostnamectl查看系统主机名。临时修改一个不同的主机名(重启后会恢复),然后用hostnamectl set-hostname改回原值。 - (实操)用
sysctl查看系统当前vm.swappiness的值。理解这个值的含义——高值意味着什么?低值呢? - (探究 🔍)查看
/etc/sysctl.d/或/usr/lib/sysctl.d/下有哪些文件。这些分片配置按什么顺序加载?找到sysctl --system的实际加载顺序文档。 - (探究 🔍)研究
/etc/security/limits.conf文件。了解如何为特定用户或组设置最大进程数、最大打开文件数等资源限制。 - (实操)用
export创建一个名为MY_NAME的环境变量,值设为你自己的名字。然后启动一个子 Shell(输入bash),用echo确认子 Shell 中也能访问该变量。输入exit返回。 - (实操)在
~/.bashrc中添加两个有用的别名(如alias myip='curl -s ifconfig.me'),然后source使其生效。测试你的别名是否工作。
点击查看答案
- (概念)`/etc` 是 Linux 配置文件的集中存放目录。本章之前实际使用过的配置文件举例:`/etc/passwd`(用户账户)、`/etc/shadow`(密码哈希)、`/etc/hostname`(主机名)、`/etc/hosts`(主机名解析)、`/etc/apt/sources.list`(软件源)、`/etc/fstab`(文件系统挂载表)。
- (概念)两者效果相同——都立即修改内核运行时参数。区别:`sysctl -w` 记录到系统日志且语法更友好。两种方式修改的参数重启后均失效,需写入 `/etc/sysctl.conf` 或 `/etc/sysctl.d/` 文件持久化。
- (实操)`timedatectl` 查看时区、本地时间、UTC 时间、RTC 时间、NTP 启用状态。如需改时区:`sudo timedatectl set-timezone Asia/Shanghai`(改为上海时区)。确保 NTP 开启:`sudo timedatectl set-ntp true`。
- (实操)`hostnamectl` 查看当前主机名和操作系统信息。临时修改:`sudo hostnamectl set-hostname temp-name`(重启后恢复)。改回原值:`sudo hostnamectl set-hostname 原主机名`。注意主机名不应包含空格。
- (实操)`sysctl vm.swappiness` 查看值(默认 60)。含义:控制系统使用 swap 的倾向程度。高值(100)更积极使用 swap,低值(10)尽可能使用物理内存。推荐:桌面 10-20,SSD 服务器 0-10,数据库服务器 0。
- (探究 🔍)`ls /etc/sysctl.d/ /usr/lib/sysctl.d/` 查看分片文件。加载顺序:`/usr/lib/sysctl.d/` → `/run/sysctl.d/` → `/etc/sysctl.d/`(后者覆盖前者)。字母序决定同目录内加载顺序。`sysctl --system` 手动重新加载所有配置。
- (探究 🔍)`/etc/security/limits.conf` 格式:`
`。domain:用户名或 @group。type:soft(软限制可超)或 hard(硬限制不可超)。item:nofile(文件句柄数)、nproc(进程数)、memlock(锁内存)。例:`@devops hard nofile 65536`。 - (实操)`export MY_NAME="你的名字"` → `bash`(子 Shell)→ `echo $MY_NAME`(确认可见)→ `exit`。注意 export 在当前 Shell 和子 Shell 有效,退出子 Shell 回到父 Shell 后变量仍在。
- (实操)编辑 `~/.bashrc` 添加 alias,例如:`alias myip='curl -s ifconfig.me'`。`source ~/.bashrc` 生效。新终端窗口自动加载。测试别名:执行 myip 应显示公网 IP。注意别名只在交互式 Shell 中生效。
学习检查点
学完本章后,请检验自己是否掌握以下内容:
| 检查项 | 自测问题 | 验证方法 |
|---|---|---|
| 概念理解 | 能用自己的话解释 /etc 目录下主要配置文件的作用 | 尝试向他人讲解 |
| 命令操作 | 能不查文档使用 hostnamectl、timedatectl、sysctl 管理系统配置 | 在终端实际执行 |
| 原理掌握 | 能说出 NTP 时间同步的工作原理和 chrony 的角色 | 画出同步流程图 |
| 故障排查 | 能独立排查系统时间和时区配置错误的问题 | 模拟故障并修复 |
| 最佳实践 | 能说明为什么修改系统配置应该优先使用 systemctl 而不是直接编辑文件 | 对比不同配置方式 |
| 用户级配置 | 能区分 login/non-login shell 的配置加载差异,并正确修改 ~/.bashrc | 运行 bash --login -x 观察 |
本章总结
Linux 的配置文化是"文本文件为王"。几乎所有系统行为都可以通过编辑 /etc 下的纯文本文件来改变。本章介绍了最重要的配置管理工具——hostnamectl(主机名)、timedatectl(时区)、localectl(语言)、sysctl(内核参数),以及从 /etc 延伸到用户级的配置体系:~/.bashrc 和 ~/.profile 定义了你的命令行工作台,环境变量(尤其是 $PATH)是"配置从文本流向进程"的最后一公里。这些工具将你的"配置意图"转化为系统为之生效的持久化设置。
速查表
| 概念 | 一句话定义 |
|---|---|
| /etc | 系统配置文件的集中存放目录 |
| hostnamectl | 查看和修改系统主机名的 systemd 工具 |
| timedatectl | 查看和设置系统时间、时区、NTP 的 systemd 工具 |
| sysctl | 读取和修改内核运行时参数的接口 |
| sysctl.conf | 内核参数的持久化配置文件 |
| *.d/ 目录 | 分片配置目录(如 sysctl.d/、sources.list.d/) |
| ~/.bashrc | 用户级 bash 配置(non-login shell 加载) |
| ~/.profile | 用户级登录配置(login shell 加载) |
| /etc/profile | 系统级登录配置(对所有用户生效) |
| 环境变量 | 影响程序行为的全局键值对;export 提升为子进程可见 |
| $PATH | Shell 搜索可执行文件的目录列表(冒号分隔) |
下一步:进入 2.3:系统信息与性能查看「系统信息与性能查看」,学习如何监控系统状态。
延伸阅读
- Linux Kernel Sysctl 文档——所有内核参数的官方说明
- 命令:
sysctl -a --pattern 'net.ipv4'——只查看网络相关的内核参数 - 配置文件黑客技巧:
bat(sudo apt install bat)——带语法高亮的 cat,浏览配置文件时非常有用 - Bash Startup Files 官方文档——各种 Shell 启动文件的完整执行顺序
- Bash 提示符自定义指南——Arch Wiki 上详尽的 PS1 教程
- 命令:
declare -p——查看所有变量的类型和值(包括环境变量、Shell 变量、函数) - 命令:
env -i command——在"干净"的环境(没有任何环境变量)中执行命令,用于测试脚本的健壮性