[GH-ISSUE #805] [Bug] 使用SSH给远程linux主机部署证书会生成一个文件夹 #546

Closed
opened 2026-03-03 01:04:13 +03:00 by kerem · 8 comments
Owner

Originally created by @800118 on GitHub (Jun 17, 2025).
Original GitHub issue: https://github.com/certimate-go/certimate/issues/805

软件版本 / Release Version

0.3.18

缺陷描述 / Description

使用SSH模式部署证书时,远程主机系统为AnolisOS23,可以看作是CentOS8的系统,使用root用户登陆SSH,部署证书的时候会在根目录生成一个以“证书文件上传路径”为名称的文件夹,不知是为何?
比如配置证书文件上传路径为/opt/web/certs/ssl.crt,会在root用户的主文件夹中生成一个名为/opt/web/certs的空文件夹

复现步骤 / Steps to reproduce

配置SSH账号
申请新证书
部署证书

日志 / Logs

# 请在此粘贴日志 / Paste logs here

其他 / Miscellaneous

No response

贡献 / Contribution

  • 我乐意为此贡献代码! / I am interested in contributing to this issue!
Originally created by @800118 on GitHub (Jun 17, 2025). Original GitHub issue: https://github.com/certimate-go/certimate/issues/805 ### 软件版本 / Release Version 0.3.18 ### 缺陷描述 / Description 使用SSH模式部署证书时,远程主机系统为AnolisOS23,可以看作是CentOS8的系统,使用root用户登陆SSH,部署证书的时候会在根目录生成一个以“证书文件上传路径”为名称的文件夹,不知是为何? 比如配置证书文件上传路径为/opt/web/certs/ssl.crt,会在root用户的主文件夹中生成一个名为/opt/web/certs的空文件夹 ### 复现步骤 / Steps to reproduce 配置SSH账号 申请新证书 部署证书 ### 日志 / Logs <details> ```console # 请在此粘贴日志 / Paste logs here ``` </details> ### 其他 / Miscellaneous _No response_ ### 贡献 / Contribution - [ ] 我乐意为此贡献代码! / I am interested in contributing to this issue!
kerem 2026-03-03 01:04:13 +03:00
  • closed this issue
  • added the
    bug
    label
Author
Owner

@800118 commented on GitHub (Jun 17, 2025):

补充截图

Image
Image

<!-- gh-comment-id:2978994749 --> @800118 commented on GitHub (Jun 17, 2025): 补充截图 ![Image](https://github.com/user-attachments/assets/7e7f0736-7377-480c-a68f-de6d19d06ef9) ![Image](https://github.com/user-attachments/assets/56aca3d1-176a-4e9f-b512-d84cf8c69f96)
Author
Owner

@usual2970 commented on GitHub (Jun 17, 2025):

没有AnolisOS23,用 centos 复现不出来

你可以把具体的执行日志贴出来

<!-- gh-comment-id:2979101570 --> @usual2970 commented on GitHub (Jun 17, 2025): 没有AnolisOS23,用 centos 复现不出来 你可以把具体的执行日志贴出来
Author
Owner

@800118 commented on GitHub (Jun 17, 2025):

使用centos8部署了好几次,这个问题是可以复现的,部署证书之后会在主目录生成一个文件夹,日志如下:

开始
[2025-06-19T02:06:01.218+08:00] [INFO] workflow is started

申请
[2025-06-19T02:06:01.219+08:00] [INFO] ready to obtain certificiate ... {"config":{"domains":"seafile.example.com","contactEmail":"exampleer@qq.com","challengeType":"","provider":"tencentcloud-dns","providerAccessId":"m9l56v9zm339w6i","providerConfig":{},"caProvider":"letsencryptstaging","keyAlgorithm":"RSA2048","skipBeforeExpiryDays":30}}
[2025-06-19T02:06:01.220+08:00] [INFO] skip this application, because the certificate has already been issued (expires in 89 day(s), next renewal in 30 day(s))

部署
[2025-06-19T02:06:01.220+08:00] [INFO] ready to deploy certificate ... {"config":{"certificate":"aeLHKiu9PUpwsnVHQUD-B#certificate","provider":"ssh","providerAccessId":"viu5i66ctx50hoq","providerConfig":{"certPath":"/opt/ssl/certimate/cert.crt","format":"PEM","keyPath":"/opt/ssl/certimate/cert.key"},"skipOnLastSucceeded":true}}
[2025-06-19T02:06:01.245+08:00] [INFO] ssh connected
[2025-06-19T02:06:01.332+08:00] [INFO] ssl certificate file uploaded {"path":"/opt/ssl/certimate/cert.crt"}
[2025-06-19T02:06:01.365+08:00] [INFO] ssl private key file uploaded {"path":"/opt/ssl/certimate/cert.key"}
[2025-06-19T02:06:01.366+08:00] [INFO] deployment completed``

<!-- gh-comment-id:2980679331 --> @800118 commented on GitHub (Jun 17, 2025): 使用centos8部署了好几次,这个问题是可以复现的,部署证书之后会在主目录生成一个文件夹,日志如下: 开始 [2025-06-19T02:06:01.218+08:00] [INFO] workflow is started 申请 [2025-06-19T02:06:01.219+08:00] [INFO] ready to obtain certificiate ... {"config":{"domains":"seafile.example.com","contactEmail":"exampleer@qq.com","challengeType":"","provider":"tencentcloud-dns","providerAccessId":"m9l56v9zm339w6i","providerConfig":{},"caProvider":"letsencryptstaging","keyAlgorithm":"RSA2048","skipBeforeExpiryDays":30}} [2025-06-19T02:06:01.220+08:00] [INFO] skip this application, because the certificate has already been issued (expires in 89 day(s), next renewal in 30 day(s)) 部署 [2025-06-19T02:06:01.220+08:00] [INFO] ready to deploy certificate ... {"config":{"certificate":"aeLHKiu9PUpwsnVHQUD-B#certificate","provider":"ssh","providerAccessId":"viu5i66ctx50hoq","providerConfig":{"certPath":"/opt/ssl/certimate/cert.crt","format":"PEM","keyPath":"/opt/ssl/certimate/cert.key"},"skipOnLastSucceeded":true}} [2025-06-19T02:06:01.245+08:00] [INFO] ssh connected [2025-06-19T02:06:01.332+08:00] [INFO] ssl certificate file uploaded {"path":"/opt/ssl/certimate/cert.crt"} [2025-06-19T02:06:01.365+08:00] [INFO] ssl private key file uploaded {"path":"/opt/ssl/certimate/cert.key"} [2025-06-19T02:06:01.366+08:00] [INFO] deployment completed``
Author
Owner

@800118 commented on GitHub (Jun 17, 2025):

centos8测试截图,经过测试发现,此问题出现于使用windows版certimate远程ssh给linux主机部署证书,如果使用linux主机给linux主机部署证书的时候则不会有这个问题

Image

Image

Image

<!-- gh-comment-id:2980805002 --> @800118 commented on GitHub (Jun 17, 2025): centos8测试截图,经过测试发现,此问题出现于使用windows版certimate远程ssh给linux主机部署证书,如果使用linux主机给linux主机部署证书的时候则不会有这个问题 ![Image](https://github.com/user-attachments/assets/f314dc79-33aa-47d5-936e-4af3447b414a) ![Image](https://github.com/user-attachments/assets/00f9ea31-736d-4faf-826e-7853cdcbaadf) ![Image](https://github.com/user-attachments/assets/a09120e4-4f28-4caa-ba10-36990d1548c2)
Author
Owner

@800118 commented on GitHub (Jun 20, 2025):

另外经测试发现,使用windows版本远程ssh部署证书的时候,前置命令和后置命令只能执行一行,在写了多条命令的情况下,并不会依次执行,而是只执行第一条命令,而linux版本没有问题。

<!-- gh-comment-id:2989591289 --> @800118 commented on GitHub (Jun 20, 2025): 另外经测试发现,使用windows版本远程ssh部署证书的时候,前置命令和后置命令只能执行一行,在写了多条命令的情况下,并不会依次执行,而是只执行第一条命令,而linux版本没有问题。
Author
Owner

@JiangJamm commented on GitHub (Jun 27, 2025):

看起来像是Windows对文件路径的处理问题

<!-- gh-comment-id:3011243221 --> @JiangJamm commented on GitHub (Jun 27, 2025): 看起来像是Windows对文件路径的处理问题
Author
Owner

@fudiwei commented on GitHub (Jun 27, 2025):

经 @JiangJamm 提醒,确认是 github.com/certimate-go/certimate@808370fd10/pkg/core/ssl-deployer/providers/ssh/ssh.go (L422-L424) 导致的。

filepath.Dir 内部会调用 filepath.FromSplash,会把路径分隔符格式化成符合本机操作系统的样子(Windows 上是 \,Linux 上是 /)。因此输入的 /path/to/folder 会在 Windows 上变成 \path\to\folder,而 Linux 上 \ 又是合法的目录名字符,所以就会创建出一个目录名为这个的空白目录出来(位置不一定是在根目录,取决于 SSH 设置的该账户默认登录目录是啥)。

@usual2970 这个问题好像还挺棘手,这是标准库提供的函数,外部没法控制。不过倒确实如 @Aerithlon 所言,这个问题只会出现在“Windows 下的 Certimate 给远程 Linux 主机部署”上。我感觉要么就只能去掉 MkdirAll 的逻辑,由用户自行确保路径存在(这种场景下 MkdirAll 其实已经是没有效果的了);要么就只能这么着了 😕

<!-- gh-comment-id:3011800274 --> @fudiwei commented on GitHub (Jun 27, 2025): 经 @JiangJamm 提醒,确认是 https://github.com/certimate-go/certimate/blob/808370fd103d5f8e03f7fb0fdbacc0f07fe7cfa1/pkg/core/ssl-deployer/providers/ssh/ssh.go#L422-L424 导致的。 `filepath.Dir` 内部会调用 `filepath.FromSplash`,会把路径分隔符格式化成符合本机操作系统的样子(Windows 上是 `\`,Linux 上是 `/`)。因此输入的 `/path/to/folder` 会在 Windows 上变成 `\path\to\folder`,而 Linux 上 `\` 又是合法的目录名字符,所以就会创建出一个目录名为这个的空白目录出来(位置不一定是在根目录,取决于 SSH 设置的该账户默认登录目录是啥)。 @usual2970 这个问题好像还挺棘手,这是标准库提供的函数,外部没法控制。不过倒确实如 @Aerithlon 所言,这个问题只会出现在“Windows 下的 Certimate 给远程 Linux 主机部署”上。我感觉要么就只能去掉 MkdirAll 的逻辑,由用户自行确保路径存在(这种场景下 MkdirAll 其实已经是没有效果的了);要么就只能这么着了 😕
Author
Owner

@JiangJamm commented on GitHub (Jun 30, 2025):

@JiangJamm 提醒,确认是

certimate/pkg/core/ssl-deployer/providers/ssh/ssh.go

Lines 422 to 424 in 808370f

if err := sftpCli.MkdirAll(filepath.Dir(path)); err != nil {
return fmt.Errorf("failed to create remote directory: %w", err)
}
导致的。
filepath.Dir 内部会调用 filepath.FromSplash,会把路径分隔符格式化成符合本机操作系统的样子(Windows 上是 \,Linux 上是 /)。因此输入的 /path/to/folder 会在 Windows 上变成 \path\to\folder,而 Linux 上 \ 又是合法的目录名字符,所以就会创建出一个目录名为这个的空白目录出来(位置不一定是在根目录,取决于 SSH 设置的该账户默认登录目录是啥)。

@usual2970 这个问题好像还挺棘手,这是标准库提供的函数,外部没法控制。不过倒确实如 @Aerithlon 所言,这个问题只会出现在“Windows 下的 Certimate 给远程 Linux 主机部署”上。我感觉要么就只能去掉 MkdirAll 的逻辑,由用户自行确保路径存在(这种场景下 MkdirAll 其实已经是没有效果的了);要么就只能这么着了 😕

@fudiwei 感谢定位问题,我创建了一个PR: https://github.com/certimate-go/certimate/pull/840 来修复这个问题。通过调用标准库的filepath.ToSlash() 对路径的分隔符重新处理为/,经测试应该是修复了这个问题了~

<!-- gh-comment-id:3018188611 --> @JiangJamm commented on GitHub (Jun 30, 2025): > 经 [@JiangJamm](https://github.com/JiangJamm) 提醒,确认是 > > [certimate/pkg/core/ssl-deployer/providers/ssh/ssh.go](https://github.com/certimate-go/certimate/blob/808370fd103d5f8e03f7fb0fdbacc0f07fe7cfa1/pkg/core/ssl-deployer/providers/ssh/ssh.go#L422-L424) > > Lines 422 to 424 in [808370f](/certimate-go/certimate/commit/808370fd103d5f8e03f7fb0fdbacc0f07fe7cfa1) > > if err := sftpCli.MkdirAll(filepath.Dir(path)); err != nil { > return fmt.Errorf("failed to create remote directory: %w", err) > } > 导致的。 > `filepath.Dir` 内部会调用 `filepath.FromSplash`,会把路径分隔符格式化成符合本机操作系统的样子(Windows 上是 `\`,Linux 上是 `/`)。因此输入的 `/path/to/folder` 会在 Windows 上变成 `\path\to\folder`,而 Linux 上 `\` 又是合法的目录名字符,所以就会创建出一个目录名为这个的空白目录出来(位置不一定是在根目录,取决于 SSH 设置的该账户默认登录目录是啥)。 > > [@usual2970](https://github.com/usual2970) 这个问题好像还挺棘手,这是标准库提供的函数,外部没法控制。不过倒确实如 [@Aerithlon](https://github.com/Aerithlon) 所言,这个问题只会出现在“Windows 下的 Certimate 给远程 Linux 主机部署”上。我感觉要么就只能去掉 MkdirAll 的逻辑,由用户自行确保路径存在(这种场景下 MkdirAll 其实已经是没有效果的了);要么就只能这么着了 😕 @fudiwei 感谢定位问题,我创建了一个PR: https://github.com/certimate-go/certimate/pull/840 来修复这个问题。通过调用标准库的`filepath.ToSlash()` 对路径的分隔符重新处理为`/`,经测试应该是修复了这个问题了~
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set.

Reference
starred/certimate#546
No description provided.