Skip to content

Linux 文件系统层次规范 FHS:软件安装的"黄金标准"

无论是通过 yumapt 安装,还是手动编译源码,Linux 软件安装都必须遵循一套底层逻辑——Filesystem Hierarchy Standard (FHS)

遵循这套规范,系统才能保持整洁,避免“依赖地狱”和文件混乱。本文将深入讲解可执行文件、库文件、配置文件和日志文件分别应该“住在哪里”。

核心原则:为什么不能随便放?

在 Windows 中,软件通常独占一个目录(如 C:\Program Files\MyApp)。但在 Linux 中,软件的文件是根据“用途”分散存储的

  • 可执行程序 集中存放(方便 $PATH 查找)
  • 配置文件 集中存放(方便备份和管理)
  • 库文件 共享存放(节省磁盘和内存)

一级目录速查表

目录作用描述关键特性
/根目录,文件系统的起点只包含子目录,不直接存放文件
/bin基本用户命令(启动时即需要的)指向 /usr/bin 的软链接(现代发行版)
/sbin系统管理命令(如 fdiskmountroot 用户主要使用
/etc配置文件大本营文本文件,几乎都是 ASCII 码
/usrUnix System Resource:系统主要资源可共享、只读,最大的目录
/varVariable:变化的数据日志、缓存、锁文件、Spool 文件
/tmp临时文件重启通常会被清空
/proc虚拟文件系统,进程信息存在于内存中(不占用硬盘)

软件安装的“黄金四象限”

对于手动安装或开发一个应用到 Linux,请严格遵循以下四个维度的存放规范:

1. 可执行程序

类型路径示例
系统自带/包管理器/usr/bin/lsgrepnginx
本地手动编译/usr/local/bin/go1.22 (手动编译版)
go install 安装~/go/bin/$GOPATH/bingo install github.com/golangci/golangci-lint/cmd/golangci-lint@latest
非系统关键服务/opt/<app>/bin//opt/goland/bin/goland.sh

💡 注意/bin 通常是 /usr/bin 的软链接;不要将自己的脚本随意放入 /usr/bin,请使用 /usr/local/bin

2. 配置文件

这是初学者最容易犯错的地方。

作用范围路径场景
全局配置/etc/<appname>/nginx.confssh/sshd_config
程序内部默认配置/usr/share/<app>/通常不建议直接修改,应复制到 /etc 覆盖
用户配置~/.config/<app>/~/.<app>rc~/.bashrc~/.gitconfig

3. 数据与日志

类型路径说明
运行时变量 (如 PID, Socket)/run/<app>/重启即消失
日志文件/var/log/<app>/需要配置 logrotate 防止占满硬盘
缓存数据/var/cache/<app>/可被删除而不影响功能
持久化数据 (数据库, 上传文件)/var/lib/<app>/比如 MySQL 的 /var/lib/mysql

4. 静态资源与文档

类型路径
文档/手册/usr/share/doc/<app>/
帮助手册 (Man Pages)/usr/share/man/man1/
图标/桌面快捷方式/usr/share/applications/ (用于 GUI)

实战:打包一个名为 myapp 的示例

假设你用 Go 写了一个守护进程叫 myapp,标准部署结构如下:

bash
# 1. 二进制文件(Go 编译产物)
/usr/local/bin/myapp

# 2. 配置文件
/etc/myapp/config.yaml
/etc/myapp/plugins/   # 子配置目录

# 3. systemd 服务文件(让开机自启)
/usr/lib/systemd/system/myapp.service

# 4. 日志(程序运行时自动生成)
/var/log/myapp/access.log
/var/log/myapp/error.log

# 5. 数据持久化(如果是个存储类应用)
/var/lib/myapp/database.db

对应的 Go 程序读取配置示例

go
package main

import (
    "fmt"
    "os"
    "gopkg.in/yaml.v3"
)

type Config struct {
    Server struct {
        Port int `yaml:"port"`
    } `yaml:"server"`
    Database struct {
        Path string `yaml:"path"`
    } `yaml:"database"`
}

func main() {
    // 标准路径:/etc/myapp/config.yaml
    configPath := "/etc/myapp/config.yaml"

    data, err := os.ReadFile(configPath)
    if err != nil {
        // 降级读取本地开发配置
        data, err = os.ReadFile("./config.yaml")
        if err != nil {
            panic(fmt.Sprintf("读取配置失败: %v", err))
        }
    }

    var config Config
    if err := yaml.Unmarshal(data, &config); err != nil {
        panic(fmt.Sprintf("解析配置失败: %v", err))
    }

    fmt.Printf("Server port: %d\n", config.Server.Port)
}

对应的 systemd 服务文件示例

ini
[Unit]
Description=My Go App
After=network.target

[Service]
Type=simple
User=myapp
Group=myapp
ExecStart=/usr/local/bin/myapp --config /etc/myapp/config.yaml

# 安全强化 - 限制文件系统访问
ReadWritePaths=/var/lib/myapp /var/log/myapp
ReadOnlyPaths=/etc/myapp

[Install]
WantedBy=multi-user.target

针对 /opt/usr/local 的选择建议

搜索该问题的读者经常纠结:我的第三方闭源软件放哪里?

场景推荐目录原因
源码编译 (go build + make install)/usr/local这是 /usr 的本地补充,包管理器不会覆盖它。
解压即用 (Go 二进制单文件)/opt/usr/local/bin/opt 适合大型静态软件包,单文件直接放 bin
商业软件 (如 Goland, Datadog Agent)/opt/<company>FHS 明确指定 /opt 用于附加应用软件包。
发行版仓库没有的包 (如手动安装 Docker)/usr/local/bin保持 /usr/bin 干净。

常见错误与纠正

  1. 错误go build -o ~/myapp 然后把二进制放家目录,通过绝对路径调用。
  • 后果:普通用户无法通过 sudo systemctl 管理,环境变量 PATH 找不到。
  • 纠正:生产环境使用 /usr/local/bin/opt
  1. 错误:将日志文件写在程序安装目录(如 /opt/myapp/logs/)下。
  • 后果:日志轮转工具 (logrotate) 默认监控 /var/log;非特权用户运行时可能因权限不足导致无法写入日志。
  • 纠正:严格遵守 /var/log
  1. 错误:手动修改 /usr/share/ 下的默认配置。
  • 后果:软件升级(覆盖 /usr/share)时,你的修改会丢失。
  • 纠正:将配置复制到 /etc/ 或在 /etc/ 中创建同名文件覆盖。

快速记忆口诀

二进制找 bin,配置找 etc

日志找 var,静态找 share

自己编译 local,大厂软件放 opt

查看当前系统的 FHS 实现

你可以通过以下命令查看你的 Linux 发行版是如何组织目录的:

bash
# 查看一级目录的挂载点
ls -lh /

# 检查 /bin 是否是软链接(现代发行版通常是)
file /bin

# 查看软件包安装的文件分别去了哪里(以 nginx 为例)
# 基于 RPM (CentOS/RHEL):
rpm -ql nginx

# 基于 DEB (Ubuntu/Debian):
dpkg -L nginx

📚 参考文献:Filesystem Hierarchy Standard (FHS 3.0) — The Linux Foundation