交叉编译openssh时,make install出现/usr/local/etc/ssh_config already exists, install will not overwrite /usr/local/etc/sshd_config already exists, install will not overwrite /usr/local/etc/moduli already exists, install will not overwrite /bin/sh: line 4: ./ssh-keygen: cannot execute binary file /bin/sh: line 9: ./ssh-keygen: cannot execute binary file /bin/sh: line 14: ./ssh-keygen: cannot execute binary file make: *** [host-key] Error 126
时间: 2025-08-26 08:54:02 AIGC 浏览: 19
<think>我们正在解决交叉编译OpenSSH时遇到的`make install`错误。错误信息包括:
1. `/usr/local/etc/ssh_config already exists`:配置文件已经存在。
2. `ssh-keygen: cannot execute binary file`:无法执行二进制文件,可能是因为交叉编译生成的二进制文件在宿主机上无法运行。
### 问题分析
1. **配置文件已存在**:在安装过程中,OpenSSH的`make install`试图将默认配置文件复制到目标目录(例如`/usr/local/etc/`),但该目录下已存在同名文件,导致安装失败。
2. **ssh-keygen无法执行**:在安装过程中,安装脚本会尝试运行`ssh-keygen`来生成主机密钥。但是,由于我们是在交叉编译,生成的`ssh-keygen`是针对目标架构的,无法在宿主机(编译时环境)上运行。
### 解决方案
#### 针对配置文件已存在的问题
我们可以通过以下方式之一解决:
- **覆盖安装**:使用`make install`时添加参数,强制覆盖现有配置文件。但OpenSSH的Makefile可能没有直接提供覆盖选项。
- **先删除现有文件**:在运行`make install`之前,手动删除已存在的配置文件(如`/usr/local/etc/ssh_config`和`/usr/local/etc/sshd_config`)。但注意,如果这些文件是之前安装留下的,且你不再需要,可以删除。不过,如果是在生产环境中,需要谨慎操作。
- **修改Makefile或安装脚本**:通过修改安装脚本,避免安装配置文件(如果不需要覆盖的话)。可以通过在配置OpenSSH时传递参数来指定不安装配置文件,但OpenSSH通常没有这样的配置选项。
实际上,OpenSSH的`configure`脚本有一个`--sysconfdir`选项,可以指定配置文件的安装路径。我们可以将其指向一个临时目录,避免与宿主机上的配置文件冲突。例如:
```bash
./configure --host=目标架构 --prefix=/usr/local --sysconfdir=/etc/ssh_temp ...其他选项...
```
这样,安装时配置文件会被安装到`/etc/ssh_temp`,而不会覆盖宿主机的`/etc/ssh`目录。然后,在目标系统上,我们可以将配置文件放到正确的位置。
但是,我们这里是在交叉编译,安装到目标目录(可能是通过`DESTDIR`指定),所以更常见的做法是使用`DESTDIR`来指定安装的根目录。例如:
```bash
make install DESTDIR=/path/to/target/root
```
这样,所有文件(包括配置文件)都会被安装到`/path/to/target/root`下,不会覆盖宿主机的文件。因此,配置文件会安装到`/path/to/target/root/usr/local/etc/ssh_config`,而宿主机上的`/usr/local/etc/ssh_config`不会被触及。
所以,如果你之前没有使用`DESTDIR`,那么现在应该使用它。同时,确保目标目录(`DESTDIR`)下的配置文件不存在,或者使用`install`命令的覆盖选项(如果Makefile支持)。
#### 针对ssh-keygen无法执行的问题
在交叉编译安装过程中,生成主机密钥需要运行`ssh-keygen`,但交叉编译的二进制文件不能在宿主机上运行。解决方法有:
1. **在目标系统上生成密钥**:先不生成密钥,等将OpenSSH安装到目标系统后,再在目标系统上运行`ssh-keygen`生成密钥。这可以通过在`make install`时跳过生成密钥的步骤来实现。
在安装时,可以通过设置`STRIP_OPT`环境变量为空来避免运行`ssh-keygen`(因为安装规则中通常会包含一个`strip`和生成密钥的步骤)。但更直接的方法是使用`make install-nokeys`(如果OpenSSH的Makefile支持)。查看OpenSSH的Makefile,我们可以发现,安装目标包括`install`和`install-nokeys`。因此,我们可以使用:
```bash
make install-nokeys DESTDIR=/path/to/target/root
```
这样,安装过程就不会尝试生成密钥,也就不会运行`ssh-keygen`。
然后,在目标系统上启动sshd之前,手动运行`ssh-keygen`生成所需的密钥(通常放在`/etc/ssh/`目录下,如`ssh_host_rsa_key`等)。
2. **使用qemu模拟运行**:如果目标架构支持用户态模拟(如使用qemu-user),可以在宿主机上安装qemu-user,然后通过binfmt_misc让宿主机能够运行目标架构的二进制文件。这样,在安装过程中就可以运行`ssh-keygen`。但这种方法较为复杂,且需要额外的配置。
### 具体步骤建议
根据以上分析,我们推荐以下步骤:
1. **配置和编译**:
```bash
./configure --host=目标架构 --prefix=/usr/local --with-配置选项...
make
```
2. **安装时跳过生成密钥并使用DESTDIR**:
```bash
make install-nokeys DESTDIR=/path/to/target/root
```
如果`install-nokeys`目标不存在(较旧版本的OpenSSH),可以尝试:
```bash
make install DESTDIR=/path/to/target/root
```
然后,在安装过程中如果遇到运行`ssh-keygen`失败,可以忽略(因为我们会手动在目标系统上生成密钥)。但这样安装过程可能会因错误而中断。因此,更好的做法是修改Makefile,注释掉生成密钥的部分。
如果必须使用`make install`且无法跳过密钥生成,我们可以提前在目标文件系统中创建好密钥(使用目标系统上的工具生成),然后在安装时使用`--with-key-dir`指定密钥目录(如果配置时支持)。或者,在安装之前,将宿主机生成的密钥(但注意,宿主机生成的密钥可能不安全,而且架构不同,密钥格式虽然相同,但通常不推荐)复制到目标文件系统的相应目录。
3. **手动生成密钥(在目标系统上)**:
将OpenSSH安装到目标系统后,在目标系统上运行:
```bash
ssh-keygen -t rsa -f /etc/ssh/ssh_host_rsa_key -N ""
ssh-keygen -t ecdsa -f /etc/ssh/ssh_host_ecdsa_key -N ""
ssh-keygen -t ed25519 -f /etc/ssh/ssh_host_ed25519_key -N ""
```
根据实际需要生成所需类型的密钥。
### 注意事项
- 使用`DESTDIR`可以避免污染宿主机的文件系统。
- 确保目标文件系统的目录结构正确,特别是配置文件和密钥的存放位置。
- 如果目标系统是嵌入式设备,可能需要调整OpenSSH的配置选项,去除不必要的功能以减小体积。
### 相关问题
1. 如何为嵌入式系统交叉编译OpenSSH?
2. 如何配置OpenSSH以减小其二进制大小?
3. 在交叉编译时,如何解决其他因需要在编译过程中运行目标架构二进制文件的问题?
4. 如何安全地生成SSH主机密钥?
### 引用说明
在解决交叉编译问题时,参考了Unix Toolbox中的相关编译和安装经验[^1][^2]。</think>### 解决交叉编译OpenSSH的安装错误
#### 错误分析
1. **`/usr/local/etc/ssh_config already exists`**
安装时检测到配置文件已存在,通常是因为:
- 宿主机已安装 OpenSSH
- 之前编译残留文件未清理
2. **`ssh-keygen: cannot execute binary file`**
交叉编译生成的 `ssh-keygen` 是目标架构的二进制文件,无法在宿主机(x86_64)上直接运行。
---
### 解决方案
#### 步骤 1:配置时指定自定义路径
通过 `--prefix` 和 `--sysconfdir` 隔离目标文件与宿主机环境:
```bash
./configure \
--host=arm-linux-gnueabihf \ # 替换为你的目标架构
--prefix=/opt/openssh-target \ # 自定义安装路径
--sysconfdir=/opt/openssh-target/etc \ # 配置文件路径
--with-default-path="" \ # 避免使用系统路径
--without-stackprotect # 禁用栈保护(某些交叉工具链需要)
```
#### 步骤 2:编译时跳过密钥生成
修改 `Makefile` 避免自动调用 `ssh-keygen`:
```diff
# 在 Makefile 中查找 install 目标
- install: keys install-sysconf
+ install: install-sysconf # 删除 keys 依赖
```
#### 步骤 3:手动安装并生成密钥
```bash
# 强制安装到自定义目录(忽略文件存在错误)
make install DESTDIR=/tmp/openssh-root STRIP_OPT=""
# 将文件复制到目标设备
scp -r /tmp/openssh-root/opt/openssh-target root@target:/usr/local
# 在目标设备上生成密钥
ssh root@target
cd /usr/local/bin
./ssh-keygen -A # 在目标架构上生成密钥
```
#### 步骤 4:清理残留文件(可选)
如果宿主机文件冲突:
```bash
sudo rm /usr/local/etc/ssh_config* # 谨慎操作!
```
---
### 关键原理
1. **路径隔离**
通过 `--prefix` 和 `--sysconfdir` 将文件限制在自定义目录,避免与宿主机冲突[^1]。
2. **密钥生成延迟**
交叉编译时跳过 `ssh-keygen` 执行,在目标设备上完成密钥生成[^2]。
3. **二进制兼容性**
目标架构二进制文件无法在宿主机运行,必须通过 `DESTDIR` 中转安装。
---
### 相关问题
1. 如何验证交叉编译的 OpenSSH 在目标设备上的兼容性?
2. 交叉编译时如何正确处理动态库依赖?
3. 如何为嵌入式系统裁剪 OpenSSH 的功能以减小体积?
4. 交叉编译中还有哪些常见工具链配置陷阱?
[^1]: UNIX/Linux 系统管理中的路径隔离原则,Colin Barschel, *Unix Toolbox*
[^2]: 交叉编译中二进制文件执行限制的解决方案,Colin Barschel, *Unix Toolbox*
阅读全文
相关推荐



















