ARTICLE DETAIL

建站实战干货

来自一线的建站与推广经验沉淀,每一条都经过真实交付验证。

Linux目录配置全掌握:FHS、路径、挂载与权限避坑指南

2026/10/2 2:23:38 拓冰建站 浏览量
Linux目录配置全掌握:FHS、路径、挂载与权限避坑指南 你第一次在Linux里安装软件时是不是也设想过到底装到哪个目录才不算乱这个问题背后恰好就是Linux目录配置的核心命题。我以前带过不少运维和开发同事他们对ls、cd、tar都熟得不能再熟但一遇到目录配置就卡壳——不是不知道 /etc 是配置目录、/var 是数据目录而是搞不清楚系统到底靠什么机制感知这些目录也不清楚权限、挂载、路径之间如何配合。说实话我早年也在目录配置上吃过亏把数据库数据直接放在家目录把编译包全部塞进 /usr/bin结果系统升级时被覆盖、磁盘被日志撑爆、甚至因为 fstab 写错导致开机进紧急模式。后来我把整个逻辑捋了一遍发现 Linux 目录配置本质上就是约定 配置 权限的三位一体。这篇文章我就把底层逻辑、核心目录、实操方案和容易翻车的坑一次讲透相信能帮你从背目录进阶到真正会配目录。1. 为什么每次配置目录都会踩坑先搞懂Linux目录设计的底层逻辑1.1 目录结构不是拍脑袋定的而是FHS约定很多人以为 Linux 目录是某位精神领袖随手创建的其实不是。绝大多数主流发行版都遵循一个公开标准Filesystem Hierarchy Standard也就是 FHS。它规定了根目录下有哪些顶层目录、每个目录应该承载什么类型的文件。注意FHS 是约定不是强制内核机制但你按它来系统管理员之间就能无障碍沟通迁移系统时也不容易翻车。有个简单的记忆方法每个顶层目录的名字几乎都有历史来源。/bin就是 binaries/sbin是 system binaries/etc来自 early 时期的 etcetera——早期啥杂七杂八的都往里丢后来慢慢沉淀为配置文件主场/var是 variable存的是经常变化的文件如日志、缓存、队列/usr最初是 user 的缩写但现在已经演化成 Unix System Resources 的语义存放系统核心的共享只读数据/lib是 library。理解了这些来源目录就再也不像一串无意义的路径了。1.2 对比Windows理解Linux的目录配置思维Windows 里目录结构按盘符铺开C盘、D盘、E盘各有各的根安装程序往往把文件丢进 Program Files、AppData、还有一堆注册表键位你要搞清楚一个软件到底写了哪里经常要翻半天。Linux 则把所有物理磁盘挂载到同一个/根目录下的不同子目录逻辑上是一棵完整的树。你要给系统配置目录实际上就是在定义某棵子树到底对应哪个磁盘、哪个分区、哪个权限域。因此目录配置在 Linux 里不是一个动作而是一个组合操作第一是物理布局决定哪个分区挂载到哪个目录第二是逻辑布局决定不同用途的软件和数据放哪里第三是访问控制决定谁能进入哪个目录、读写哪个目录。排查目录相关的问题时只要按这三层逐个检查基本不会漏。1.3 系统知道去哪里找才是配置的本质为什么配置了 PATH 才能运行命令为什么某些程序运行前要设置LD_LIBRARY_PATH为什么 Nginx 启动时会读取/etc/nginx/nginx.conf因为 Linux 里的程序和进程都有自己默认的搜索路径而目录配置的本质就是把这些路径指向正确的地方。你在/etc/environment里写一行JAVA_HOME/usr/local/jdk系统的 Java 相关脚本才能通过$JAVA_HOME/bin/java找到二进制文件。所以我认为学目录配置不单是要背目录名而是要在脑海里建立一张搜索地图配置文件在哪、可执行文件在哪、库文件在哪、运行时数据在哪、日志在哪。这张图越清晰排障越快。2. 核心目录吃透从根目录到home每一层该放什么2.1 一张表搞懂几乎所有顶层目录我平时讲课喜欢先给一张总表让新人挂在办公位前目录主要用途放什么类型/bin系统基础命令ls、cp、cat等二进制/sbin系统管理命令fdisk、mkfs、sysctl等/lib基础动态库与内核模块.so文件、modules/usr系统只读的共享数据应用程序、库、文档/usr/local本地管理员安装的软件手动编译安装的程序/etc系统与软件的配置文件几乎都是.conf文件/home普通用户家目录用户个人数据和配置/rootroot 用户家目录管理员个人文件/var经常变化的文件日志、缓存、spool、lib/tmp临时文件重启后可能清理/dev设备文件磁盘、终端、USB/proc进程和内核虚拟文件系统运行中的进程信息/sys内核设备、驱动、总线信息sysfs 虚拟文件/opt第三方大型软件商业软件、独立安装包/srv服务站点数据Web 站点、FTP 数据/mnt、/media临时挂载点光盘、U盘、其他分区这里特别提醒新人/proc和/sys不是真实磁盘上的文件它们是内核暴露出来的虚拟接口直接 echo 可以改内核参数随意写入可能把系统调乱操作前弄清再下手。2.2/usr和/usr/local的边界很多人搞反了在 Ubuntu、Debian 等发行版里包管理器apt、dpkg安装的软件系统组件默认进入/usr/bin、/usr/lib、/usr/share而你自己从源码编译安装的软件主流做法是放到/usr/local。为什么因为包管理器升级软件时很可能覆盖掉/usr下的同名文件而/usr/local/bin的优先级在大多数发行版里默认比/usr/bin更高取决于 PATH 顺序。你把源码编译的东西装进/usr/local既能避免和系统包冲突又能保证升级系统包时不会被误伤。类似地/opt用来放独立打包的第三方软件比如 JetBrains 的 IDEA、Google Chrome、一些闭源 SDK。这些软件往往自带完整的 bin、lib、share 结构放进/opt/xxx后在/usr/local/bin下做一个软链接就能像普通命令一样使用了。2.3/var不是垃圾堆它有清晰的子结构看/var底下好像什么都有其实规则很明确/var/log放日志比如syslog、nginx/access.log/var/lib放系统软件运行期间产生的持久化数据比如 MySQL 的datadir、dpkg的 rpm 数据库/var/cache放缓存可删可重建/var/spool放待处理队列比如邮件队列、打印任务/var/tmp比/tmp更稳定系统重启后不一定被清空适合放临时且跨重启的数据。如果你在一台机器上部署应用建议遵循这套规则而不是把日志丢到/home/user/log把数据库数据丢到/data/random否则后续备份、监控、排障都会变得很别扭。2.4/srv和挂载点的用意/srv专门存放系统提供服务产生的数据例如/srv/www放网站代码、/srv/git放 Git 仓库。很多发行版默认并没有srv下的子目录需要管理员自己规划。有人觉得/srv和/var/www有点重叠其实/var强调动态变化而/srv更强调服务的业务数据语义上/srv更适合独立分离的数据盘。至于/mnt和/media一个是临时挂载点比如手动挂载 NFS、新硬盘另一个是系统自动挂载可移动设备的位置。习惯上不要把长期业务数据挂到/mnt下因为/mnt本身就表示临时。想深入了解本机目录定义建议执行man hier当年的我们对 man 文档读得越透后面坑踩得越少。3. 实战一套可落地的目录配置方案环境变量、软件路径、数据分离3.1 配置 PATH你说的找不到命令多半是它造成的PATH 是 shell 在解析命令时搜索可执行文件的目录列表用冒号分隔。配置 PATH 时的核心原则是知道在哪一层改才知道什么时候生效。临时生效export PATH/the/path:$PATH只在当前终端有效用户永久生效写入~/.bashrc或~/.profile新开的这个用户 shell 生效系统级生效写入/etc/profile.d/下新建.sh文件例如vim /etc/profile.d/myenv.sh所有用户登录时都会 source全局环境文件写入/etc/environment它用来存全局变量但不是脚本不支持变量展开注意别在里面写$PATH。我推荐把自定义路径放到/etc/profile.d/下单独建一个文件比如custom_path.sh可读性好、回滚方便。写完后用source /etc/profile或重新登录即可。3.2 软件安装目录的选择源码编译与绿色软件源码包编译安装时./configure --prefix/usr/local/nginx-1.24可以指定安装目录。为什么这么写因为要让系统知道这版程序的所有文件都在一个自包含的目录里之后做版本切换时直接改软链接即可。举个例子我安装 JDK 时通常会mkdir -p /usr/local/java tar -zxvf jdk-17_linux-x64_bin.tar.gz -C /usr/local/java ln -s /usr/local/java/jdk-17.0.2 /usr/local/java/current然后配置环境变量cat /etc/profile.d/jdk.sh EOF export JAVA_HOME/usr/local/java/current export PATH$JAVA_HOME/bin:$PATH EOF这里把/usr/local/java/current做成一个软链以后升级 JDK 时只要更换current指向即可环境变量完全不用动。这种目录 软链的组合是目录配置里最高频的套路。3.3 数据目录规划应用数据、日志、代码分离如果只是临时测试你可以把站点代码放/home/user/project但生产环境我强烈建议做数据目录分离。一个比较通用的结构是/srv/myapp 应用代码与资源 /srv/myapp/log - /var/log/myapp或把日志直接配置到 /var/log/myapp /var/lib/myapp 应用状态数据 /opt/myapp 依赖的执行程序包 /etc/myapp 应用配置文件为什么要这样拆因为备份策略往往按目录区分代码目录可能建了 Git 仓库数据目录必须做快照或定期备份日志目录还要纳入日志轮转和集中采集。混在一起备份和排查都难受。比如 PostgreSQL 的data_directory通常指向/var/lib/postgresql/15/main我们也可以把它改到独立数据盘/data/pgdata通过修改 postgresql.conf 和 systemd 单元文件实现。这样即使系统盘坏了数据盘还能救回来。3.4 独立磁盘挂载配置fstab 的正确写法现在很多云服务器在系统盘之外挂了一块数据盘。把分区挂载到业务目录下涉及/etc/fstab的配置。一个典型的使用 UUID 挂载的配置UUID3a8c1b2c-... /data ext4 defaults,noatime 0 2需要注意别用设备名如 /dev/vdb1因为设备名在重启后可能变化改完 fstab 先执行mount -a验证0 2表示该分区的开机自检顺序根分区是0 1普通分区是0 2。我见过太多人因为 fstab 写的挂载目录不存在或者 UUID 抄错导致开机直接进 emergency mode。解决办法也不难在紧急模式下用只读方式执行mount -o remount,rw /然后修复 fstab再reboot。3.5 权限配置只有 root 和属主有权限才是正常的目录配置里权限是临门一脚。创建好目录后必须用chown、chmod设置属主与模式mkdir -p /srv/myapp chown -R deploy:deploy /srv/myapp chmod -R 750 /srv/myapp解释一下750表示属主可读写执行、属组可读执行、其他用户无权限。很多新人图省事直接chmod 777 /srv/myapp这在共享的临时目录还能忍在业务目录里就是给自己埋雷任何本地用户都能改写你的站点代码或数据一旦被入侵后果非常严重。另外注意/tmp目录的权限是1777这个1是粘滞位sticky bit含义是只有文件属主、目录属主或 root 能删除文件这是多用户临时目录的基本保护。配置完权限后建议用ls -ld /srv/myapp验证一下。3.6 用 du 和 df 判断谁占满了磁盘目录配置做得再好系统跑久了也会出现空间告警。排查路径非常固定先df -h看哪个挂载点满了再用du -sh /var/log/* | sort -hr | head -n 10定位具体目录。常见占盘大户是/var/log/journalsystemd 日志、/var/lib/docker容器镜像和层、core dump 文件、旧内核包。定位到目录后再考虑扩容、清理或迁移。记住df看的是文件系统占用du看的是目录实际大小两者口径不一致很常见尤其当有文件被删除但仍然被进程占用时df会虚高。4. 目录配置中最容易翻车的几个场景及排查链路4.1 PATH 配置错误导致命令找不到现象执行java、node、mycli等自定义命令时 shell 提示command not found。排查链路先看目标文件在不在ls -l /usr/local/bin/java打印当前 PATHecho $PATH确认是否包含目标目录检查你写的配置cat /etc/profile.d/jdk.sh确认配置是否被执行source /etc/profile.d/jdk.sh后重新which java如果脚本里有export PATH/usr/local/java/bin漏了$PATH会导致现有命令全部消失连ls都不好使这就是典型的路配错毁全局。我建议把export PATH/path/to/bin:$PATH中$PATH保持在后面并且永远先备份原 PATHecho $PATH ~/path.bak。一旦把系统 PATH 覆盖你还能手动恢复。4.2 软链接断裂导致目录无感消失现象访问/usr/local/bin/foo提示No such file or directory但明明在/opt/foo/bin/foo能看到文件。原因/usr/local/bin/foo是指向/opt/foo/bin/foo的软链接而该链接的绝对或相对目标写错或者目标被移动了。排查用ls -l /usr/local/bin/foo看链接指向用readlink -f /usr/local/bin/foo解析最终路径如果目标里还有嵌套目录就尤其小心软链接如果写的是相对路径它的解析基准是链接所在目录容易懵。我建议在写链接时一律使用绝对路径ln -s /opt/foo/bin/foo /usr/local/bin/foo。如果想保留相对路径先cd /usr/local/bin再ln -s ../../opt/foo/bin/foo foo逻辑才能对。4.3 fstab 配置错误导致开机失败现象开机进入紧急模式提示 mount failure 或 cant find UUID。原因/etc/fstab的挂载项写错 UUID、目录不存在或加了不受支持的挂载参数。排查链路在紧急模式下先执行mount -o remount,rw /把根目录切成可写查看 fstabcat /etc/fstab把可疑的挂载行注释掉用blkid查询真实的 UUID用mount -a重新加载所有挂载项检查是否报错确认没问题后reboot。这里提醒不要盲目删除 fstab 行只注释掉后面有机会再补。我的习惯是每次改完 fstab立即执行mount -a如果有报错就地修复绝不让错误配置留到重启时爆发。4.4 Permission denied 的一步步定位现象能ls到目录但无法进入或无法读写。排查链路id查看当前用户 uid/gidls -ld 目标目录查看目录属主、属组、权限位检查上一层目录是否具备执行权限因为进入目录至少需要 x 权限如果目录开启了 SELinux还要看上下文ls -Z修复chown改属主、chmod urwx加权限或setfacl -m u:user:rwx dir使用 ACL 精细控制。权限问题最容易骗人你能读目录里文件名但不一定能访问文件内容因为目录的读权限和文件的读权限是两回事。我调试时习惯一口气把路径从/到目标目录逐层namei -l /path/to/target看权限很多疑虑立刻化解。4.5 日志和容器数据把根目录塞满现象df -h显示/100%但不知道什么东西占的。典型场景systemd journal 日志积累、Docker 的 overlay2 目录、Nginx access_log 不轮转、PostgreSQL 的 WAL 文件积累。处理步骤df -h找出满的分区du -x --max-depth2 / | sort -hr | head -n 20从根往下扫-x避免跨文件系统很重要看到/var/log/journal很大就运行journalctl --vacuum-time3d清掉 3 天前的日志控制 journal 大小上限可改/etc/systemd/journald.conf的SystemMaxUse500M看到/var/lib/docker很大用docker system prune清理悬停镜像和构建缓存必要时把整个 Docker 数据目录迁移到独立盘按后面 bind mount 的方式。目录配置不只是初始规划还包括Runtime 的维护性策略没有轮转和清理机制再好的结构也会爆。5. 进阶目录配置的几个实用技巧与原则5.1 用最小权限给目录做安全兜底生产目录配置有一个原则能不给就不给能只读就不要写。例如 Web 站点代码目录对运行用户只给读写执行对其他用户只给读和进入配置目录和密钥目录连读都不给其他用户开。如果确实需要某个用户访问优先用 ACL 精确设置而不是chmod 777。我在管理服务器时会为每个服务创建独立系统用户useradd -r -s /usr/sbin/nologin myapp然后把资源目录chown myapp:myapp这样即使 Web 进程被攻破它能访问的目录范围也被锁死在一个业务目录下。5.2 用 GNU Stow 管理手动安装的软件目录如果你经常编译安装软件目录配置最怕的是/usr/local/bin下散落一堆二进制却不知道各自属于哪个版本、怎么回退。GNU Stow 的思路是你把每个软件包放在/usr/local/stow/nginx-1.24/然后执行stow nginx它会自动在/usr/local/bin等目录下建立指向/usr/local/stow/nginx-1.24/bin的软链接。卸载时执行stow -D nginx链接干净移除目录结构一目了然。这让我在切换 nginx 版本、OpenSSL 版本时几乎零失误。5.3 用 bind mount 迁移大目录不用移动数据当某个目录比如/var/lib/docker所在分区不够但另一个盘还有大量空间时常见的迁移方式是mv数据再改 fstab。但如果你不想改动应用配置或者目标文件系统不能被卸载可以用 bind mount 把一个已有目录挂到另一个位置比如mkdir /docker-data # 把原 /var/lib/docker 的数据复制到 /docker-data rsync -av /var/lib/docker/ /docker-data/ mount --bind /docker-data /var/lib/dockermount --bind让/var/lib/docker这个挂载点变成/docker-data的别名应用程序完全无感知。要永久生效在 fstab 中写/docker-data /var/lib/docker none bind 0 0这招特别适合目录配置不能断服务的场景。注意 bind mount 不会自动递归如果要挂载嵌套的子挂载点可以用rbind或逐个绑定。5.4 给日志目录加上轮转别等爆盘才处理很多默认安装的软件自带 logrotate但自定义应用往往需要自己配置。例如/etc/logrotate.d/myapp/var/log/myapp/*.log { daily rotate 14 compress delaycompress missingok notifempty create 0640 myapp myapp }这里daily按天轮转rotate 14保留 14 份compress压缩旧日志。配置完成后可用logrotate -d /etc/logrotate.d/myapp做一次 dry-run 检查。目录配置里日志往哪写和日志怎么清理是同一件事你只配目录不配轮转等于只挖坑不埋。5.5 目录配置的文档化意识多人维护的服务器最忌讳目录配置全靠口头相传。我会在/srv或/opt下留一个README.txt写清楚这个目录是谁在什么时候创建的代表哪个应用打包方式是什么数据是否需要备份备份到什么位置权限模型和关联的 systemd 服务名。这样后来者接手时不用对着/opt下几十个目录猜来猜去。我在团队里把这个文件称为目录配置的注释相比代码注释它救过的场景多得多。最后说一点个人习惯。我每配一台新机器第一步永远不是急着安装软件而是先把目录树画一遍系统盘放什么数据盘哪块日志在哪备份在哪权限怎么分。这个习惯坚持下来之后几乎所有目录规划问题都能在装第一个包之前解决完。目录配置其实一点也不难只要抓住系统约定的路径 你自己的业务挂载 严格的权限这三块你就能把 Linux 的骨架打得很稳。