repo 与 index:站点目录该怎么切

1Panel 的站点目录是 /opt/1panel/www/sites/<域名>/,里面的一切都归面板管。在面板上点一次「删除网站」,它会把整个目录清掉,不问你里面有什么。

这个坑我踩过一次,我当时把仓库克隆到了站点目录里,路径是 sites/<域名>/repo。后来发现建站参数不对,删掉重建,仓库跟着一起没了。

这个坑踩完后得出这么一个结论:站点目录只放网站运行需要的东西,代码仓库放站外。

建两个目录:/opt/repos/<域名>/ 放 git 仓库,拉取和更新都在这边发生,由我 git pull。/opt/1panel/www/sites/<域名>/index/ 是站点运行目录,Web 直接读这里,由面板和 rsync 写。

两步更新:

bash 复制代码
# ① 站外仓库拉最新
cd /opt/repos/<域名> && git pull

# ② 同步进站点目录
rsync -a --delete --exclude={'...'} \
  /opt/repos/<域名>/<代码在仓库中的相对路径>/ \
  /opt/1panel/www/sites/<域名>/index/

源路径结尾那个斜杠

它决定的是平铺还是嵌套。带 / 是把内容铺进目标,结果是 index/app/、index/public/。不带 / 是把目录本身放进目标,结果是 index/<项目名>/app/。

我们用的是带 / 的写法。所以站点根下面直接就是 app/ config/ public/,中间没有多一层项目目录。

这一点会一路影响到后面:所有写路径的地方,少一层或者多一层,命令都是找不到文件。

为什么不在站点里 clone 完就地 pull

听起来省事,连 rsync 都省了。原因是:

一是删站连坐,就是开头那件事:一次删除网站,仓库连同没提交的改动一起消失。

二是 .git/ 和 Web 目录混住。版本数据、工作区、网站运行目录三层叠在一起,而 Web 目录的权限必须对 PHP 进程开放,等于顺手把 .git/ 也放进了这个权限面里。

所以宁可多一步 rsync。仓库是仓库,站点是站点,中间靠一次同步动作连起来。

这么分还有个顺带的好处:出问题时你能马上回答这个文件是谁生成的。git 同步来的、composer 装的、还是面板自己写的,三种答案对应三种处置方式。

8 项排除

rsync -a --delete 里的 --delete 是个危险开关:它让目标和源完全一致,源里没有的,目标里就被删掉。

凡是不该被删的东西都得显式排除,清单最后长到 8 项:

bash 复制代码
rsync -a --delete \
  --exclude='.env' \
  --exclude='runtime/' \
  --exclude='vendor/' \
  --exclude='.git/' \
  --exclude='public/static/' \
  --exclude='public/storage/' \
  --exclude='.user.ini' \
  --exclude='404.html' \
  <源>/ <目标>/

.env 是生产配置,只存在于服务器上,仓库里根本没有,被 .gitignore 忽略。不排除,它会被判成多余删掉。

runtime/ 是框架的运行时目录,缓存、日志、编译产物都在里面,同样是服务器上产生、仓库里没有。

vendor/ 也一样,被 .gitignore 忽略,不在仓库里。

.git/ 是版本数据,跟网站运行无关。

public/static/ 是静态资源目录,被 git 全量忽略,忽略内容是写死的 *,手动上传的 logo 这类东西都在里面。

public/storage/ 是用户上传文件的落盘位置,这是业务数据,删了就是事故。

.user.ini 和 404.html 都是面板建站时自动生成的,一个是 open_basedir 之类的加固配置,一个是错误页。

后四项有个共同点:不在仓库里,但服务器上必须有。

而 rsync --delete 的逻辑是以源为准,源里没有的它就要删。这四样在源里都不存在,不排除就一定会没。

第 6 项尤其要注意!那是用户上传的图片,一次代码更新把用户数据删光,发生一次就够了。

能不能干脆不用 --delete

可以,代价是源里删掉的文件在目标里一直留着。时间一长,站点目录里堆着一批仓库里早就没有、服务器上还在跑的陈旧文件。排查时你面对的不是当前代码,而是一份历史沉积:同一个类为什么会有两个文件、哪个才是真正被加载的,全得靠猜。

所以 --delete 本身值得留着,代价只是那份清单得维护。真正要留意的是那份清单有没有被维护,而不是这个开关。

8 项其实只有三类

第一类是启动必需件:.env、vendor/、runtime/,分别靠手工建、composer install、mkdir 生成,漏了站点直接跑不起来。

第二类是用户数据:public/static/ 和 public/storage/,手工上传或者用户自己上传,漏了是图片 404、上传功能异常。

第三类是面板生成物:.user.ini 和 404.html,漏了是加固配置丢失、错误页失效。

.git/ 不属于任何一类,它纯粹是跟这里无关的东西。

重点在第一类。它有个反直觉的地方:这几样之所以要被排除,恰恰因为它们不是代码;可它们又必须存在,否则站点起不来。

于是就有了一个很隐蔽的坑。部署流程只写了「排除什么」,没写「排除之后由谁生成」,第一类就一定会漏。

而且漏得毫无察觉:rsync 不回显任何异常,目录列表看起来完全正常,直到你去访问站点才发现页面打不开。

这个坑的完整现场,从页面打不开一路定位到 vendor/ 缺失,见《页面打不开不是 Nginx 的错》那篇。

同步完之后先看三样

不要同步完就去访问网站。

bash 复制代码
cd /opt/1panel/www/sites/<域名>/index

# ① 依赖在不在(没有就装)
ls vendor/autoload.php

# ② 配置在不在(没有就建)
ls .env

# ③ 运行时目录可不可写(注意看的是「写」权限)
ls -ld runtime

第三项最容易看漏。目录存在不等于可写。容器里跑 PHP-FPM 的身份如果落在目录属主的 other 组,权限就得给够,光有 r-x 不够,它需要的是 w。

属主已经改对了也不代表没问题:如果这个目录是在改属主之后才由 root 创建的,属主又会变成 root。

三条经验

代码放站外。站点目录归面板管,面板删站的时候不会问你。

--delete 的排除清单,等于一份「必须手工补回」的清单。每排除一项,就问一句「谁来生成它」。

rsync 成功不等于部署成功。它只保证文件同步完成,不保证站点能跑起来。

目录这一层做对了,后面所有命令才有一个稳定的立足点:路径不会忽多忽少一层,文件也不会莫名其妙消失。

相关推荐
用户EasyAdminBlazor1 小时前
EasyAdminBlazor 日志系统源码解析:为什么数据库日志需要有界队列?
后端
Sylven1 小时前
【DevOps 开发流程】问题+标签驱动开发,可视化你和AI的开发进度
后端
松就是我902981 小时前
Agent系统设计七条通用原则-CSDN
后端
那就叫王师傅1 小时前
AD基础学习01
后端
付威20231 小时前
Rust 1.99 更新了什么?一个新手视角的升级前后对比
人工智能·后端
我的div丢了肿么办1 小时前
进程和线程以及go语言中的协程
后端·go
墨家句子1 小时前
4G 显存老显卡怎么跑模型:llama.cpp 加 GGUF 配置
linux·后端
HLAIA光子1 小时前
RAG Chunks 切分优化后成本骤降 86%
后端·性能优化·架构
后端LV1 小时前
Caffeine 快到 1450 万 ops/s,为什么我还是不敢说数据一致
java·后端