设置 linux 发布网站时文件夹的权限
最近重新搞起网站,太久没弄linux ,东西全忘干净了,特作此记录。
www 作为 Web 服务器用户,也就是执行 Nginx 等软件的用户。 perter 作为普通用户,是登陆服务器做各种操作的用户,尽量不使用 root 用户。
要让 www 和 peter 两个用户都能读写 /www/wwwroot/blog 目录,同时确保 peter 能通过 rsync 上传文件,而 www 能读取文件(例如作为 Web 服务器用户),可以按照以下步骤进行权限配置:
1. 修改目录所有权和权限
(1) 将目录所属组改为 www 或共享组
sudo chown -R root:www /www/wwwroot/blog # 所有者 root,组 www root 保持所有者(避免安全问题,防止普通用户篡改关键目录)。
www 作为组(让 Web 服务器用户 www 和上传用户 peter 都能访问)。
(2) 设置目录权限
sudo chmod -R 2775 /www/wwwroot/blog # 设置 SGID,保证新文件继承组权限
2775 权限详解:
2:启用 SGID(新创建的文件/目录会继承父目录的组 www)。
1 2 3 4 5 6 7
775: 所有者 root:读写执行(7)。 组 www:读写执行(7)。 其他用户:读执行(5)。
2. 将用户 peter 加入 www 组
1
sudo usermod -aG www peter # 将 peter 加入 www 组
确保 peter 在 www 组中,才能拥有组权限。
3. 配置 rsync 以保留正确的权限, rsync用于与服务器同步文件
peter 用户使用 rsync 时,需确保新文件继承正确的组权限:
1
2
3
# 对现有目录
sudo chmod -R u+rwX /www/wwwroot/blog
sudo chown -R peter:www /www/wwwroot/blog
www:是网络用户组,用于网站的操作,nginx 是此用户组的 www 用户(宝塔中nginx 为 www 用户)
设置setgid保证未来文件继承组权限
1
sudo chmod g+s /www/wwwroot/blog
4. 验证权限
(1) 检查目录权限
1
ls -ld /www/wwwroot/blog
预期输出:
1
drwxrwsr-x root www /www/wwwroot/blog
rws 中的 s 表示 SGID 生效。
(2) 检查新创建的文件
1
2
touch /www/wwwroot/blog/test.txt
ls -l /www/wwwroot/blog/test.txt
预期输出:
1
-rw-rw-r-- root www /www/wwwroot/blog/test.txt
文件组应为 www,权限为 664。
5. 处理特殊情况
(1) Web 服务器用户 (www) 需要写入权限 如果 www 需要写入(如上传文件),需确保:
1
sudo chmod -R g+w /www/wwwroot/blog # 为组添加写权限
(2) SELinux 环境(如 CentOS/RHEL) 如果启用 SELinux,需调整上下文:
1
sudo chcon -R -t httpd_sys_content_t /www/wwwroot/blog # 允许 Web 服务器访问
最终总结
操作 命令/配置 修改目录所有权
1
2
3
4
5
6
7
8
sudo chown -R root:www /www/wwwroot/blog 设置 SGID 和权限
sudo chmod -R 2775 /www/wwwroot/blog 将 peter 加入 www 组
sudo usermod -aG www peter rsync 同步时所需要的文件权限命令
sudo chmod -R u+rwX /www/wwwroot/blog
sudo chown -R peter:www /www/wwwroot/blog
常见问题
- Q:为什么用 2775 而不是 775?
2775 的 SGID 确保新创建的文件自动继承 www 组,避免手动修复组权限。
- Q:peter 上传的文件为什么还是属于 peter 的组?
如果没有 SGID 或 –chown=:www,文件会保留上传用户的默认组。确保两者之一已配置。
- Q:Web 服务器 (www) 仍然无法读取文件?
检查 SELinux 或 AppArmor 限制,或确认 www 用户确实在 www 组中:
1
groups www # 检查 www 用户的组
按此配置后,peter 和 www 均可安全读写目录,且 rsync 同步的文件能直接被 Web 服务器使用。本文的 rsync 同步直接使用 peter 用户,所以不配置 rsync 的单独权限。
配置 github actions 同步 Jekyll 静态网站到服务器的工作流
在 github pages 后发布了网站后,想同步更新到服务器只需要用 github actions 的工作流就行了,它能直接调用 rsync 的同步功能。
先在 github 项目中选择 settings - Secrets and Variables - Actions ,在页面中点击 New repository Secrets 中添加 github 登陆个人服务器的环境变量:
1
2
3
4
SERVER_DEPLOY_PATH : 静态网站要部署的目录
SERVER_IP : 服务器的ip 或域名
SERVER_USER : 服务器中等登陆的用户
SSH_PRIVATE_KEY : 使用ssh 登陆服务器时所使用的密钥对中的私钥,需提前在服务器配置好
在 .github/workflows/pages-deploy.yml 的脚本如下:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
name: "Build and Deploy"
on:
push:
branches:
- main
- master
paths-ignore:
- .gitignore
- README.md
- LICENSE
# Allows you to run this workflow manually from the Actions tab
workflow_dispatch:
permissions:
contents: read
pages: write
id-token: write
# Allow one concurrent deployment
concurrency:
group: "pages"
cancel-in-progress: true
jobs:
build:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v4
with:
fetch-depth: 0
# submodules: true
# If using the 'assets' git submodule from Chirpy Starter, uncomment above
# (See: https://github.com/cotes2020/chirpy-starter/tree/main/assets)
- name: Setup Pages
id: pages
uses: actions/configure-pages@v4
- name: Setup Ruby
uses: ruby/setup-ruby@v1
with:
ruby-version: 3.3
bundler-cache: true
- name: Build site
# 注意这里使用了 _site$ 作为构建目标目录
# 这通常是为了适应 GitHub Pages 的子目录部署
# 同步到你的服务器时,你可能需要将这个目录内容部署到服务器的网站根目录
# 或者你也可以选择将 Jekyll build 的目标目录改为 _site,然后同步 _site 目录
# 这里我们假设你直接同步这个带 base_path 的目录内容
run: bundle exec jekyll b -d "_site$"
env:
JEKYLL_ENV: "production"
- name: Test site
run: |
bundle exec htmlproofer _site \
\-\-disable-external \
\-\-ignore-urls "/^http:\/\/127.0.0.1/,/^http:\/\/0.0.0.0/,/^http:\/\/localhost/"
# 上传用于 GitHub Pages 的 artifact
- name: Upload site artifact for Pages
uses: actions/upload-pages-artifact@v3
with:
path: "_site$"
# actions/upload-pages-artifact 默认会命名 artifact 为 "github-pages"
# 部署到 GitHub Pages 的 Job (保持不变)
deploy_pages:
environment:
name: github-pages
url: $
runs-on: ubuntu-latest
needs: build # 依赖 build Job
steps:
- name: Deploy to GitHub Pages
id: deployment
uses: actions/deploy-pages@v4
# 新增的 Job:部署到你的独立服务器
deploy_to_server:
runs-on: ubuntu-latest
needs: build # 依赖 build Job,确保在构建完成后才执行
# 可以选择添加 condition 来控制何时部署到服务器,例如:
# if: github.ref == 'refs/heads/main' # 只在推送到 main 分支时部署到服务器
steps:
- name: Download site artifact
# 下载 build Job 上传的 artifact。actions/upload-pages-artifact 默认名称是 "github-pages"
uses: actions/download-artifact@v4
with:
name: github-pages # 确保这里是 build Job 上传 artifact 时使用的名称
# path: ./downloaded-site # 可以指定下载路径,不指定则默认下载到工作目录
- name: Deploy with rsync
# 使用 easingthemes/ssh-deploy Action 通过 rsync 同步文件
# 确保你已经在 GitHub 仓库 Settings -> Secrets 中添加了必要的 Secrets
uses: easingthemes/ssh-deploy@main
with:
# 必须配置的 Secrets
SSH_PRIVATE_KEY: $ # 你的服务器 SSH 私钥
REMOTE_HOST: $ # 服务器 IP 地址或域名
REMOTE_USER: $ # SSH 登录用户名
TARGET: $ # 网站文件在服务器上的目标路径 (例如 /var/www/your-site)
# rsync 同步参数 (推荐)
# 可以排除某些文件或目录不同步
# --exclude='.jekyll-cache' # 排除 Jekyll 缓存目录
# 排除不需要同步或删除的文件/目录
# 加入 .user.ini 以防止 --delete 参数删除它
ARGS: --archive --verbose --compress --delete --no-times --exclude='.user.ini' --exclude='.jekyll-cache'
# --archive: 归档模式,保留文件权限、时间戳等
# --verbose: 显示详细输出
# --compress: 传输过程中压缩数据
# --delete: 删除服务器上目标目录中在本地源目录中不存在的文件 (确保服务器内容与本地完全一致)
# 要同步的本地目录
# 下载的 artifact 会恢复 _site$ 目录结构
# 你需要将这个目录的内容同步到服务器的目标路径
# 如果你的服务器目标路径就是网站根目录,那么 SOURCE 就应该是这个目录本身的内容
# 根据你的 Jekyll 构建配置 (`-d "_site$"`),
# 下载的 artifact 会在工作目录下创建 _site/your_base_path/ 这样的结构
# rsync 的 SOURCE 需要指向实际的静态文件目录
# 通常情况下,_site/ 下的内容就是你需要同步的
SOURCE: ./ # 假设下载的 artifact 在工作目录下恢复了 _site 目录结构
- name: Extract artifact.tar on server
# 使用 appleboy/ssh-action 连接到服务器并执行解压命令
uses: appleboy/ssh-action@master
with:
host: $
username: $
key: $
script: |
# 检查文件是否存在(可选,但推荐)
if [ -f /www/wwwroot/blog/artifact.tar ]; then
echo "artifact.tar found, extracting..."
# 进入目标目录并解压 artifact.tar 到当前目录(即 /www/wwwroot/blog)
tar -xf /www/wwwroot/blog/artifact.tar -C /www/wwwroot/blog/
echo "artifact.tar extracted."
# 如果需要,可以在此处删除 tar 包
rm /www/wwwroot/blog/artifact.tar
else
echo "artifact.tar not found in /www/wwwroot/blog/, skipping extraction."
fi
- name: Server Deployment successful
run: echo "Deployment to server completed successfully!"
如果一切顺利在 github actions 工作流中没有错误就能在服务器中看到同步的静态网站文件了。
至于部署网站,直接使用宝塔面板添加静态网站,nginx 读取就完事了,也不用费心。