资讯动态

OpenSSH移植到FS4412开发板实战:交叉编译与远程登录完整指南

发布时间:2026/10/17 23:33:22 来源:尧图企业网站定制
做嵌入式开发的人多少都有过这种体验板子摆在实验台角落串口转接线的 USB 头被各种杜邦线层层缠住想敲一条命令得先把椅子挪过去蹲在地上对着一行行日志发呆或者板子人在一个房间机器在另一个房间改个配置要来回跑好几趟调试效率低到让人怀疑人生。这种时候给开发板移植一套 OpenSSH让板子接入局域网、可以被远程安全登录就是一笔怎么算都划算的投资。这篇博文围绕的核心工作是把 OpenSSH 移植到 FS4412 开发板上。FS4412 是基于三星 Exynos4412 四核 ARM Cortex-A9 处理器的一块典型嵌入式 Linux 开发板实验环境里常拿它做系统移植、驱动开发和综合项目。我们最终要实现的效果是板子启动后能在局域网内被任意一台电脑通过 SSH 协议远程登录能传文件、能抓日志、能执行命令彻底摆脱物理距离和串口线的束缚。整个过程会完整覆盖三个开源组件的交叉编译zlib、OpenSSL、OpenSSH以及它们如何集成进根文件系统、如何生成密钥、如何配置并启动 sshd、如何排查那些经典的坑。适合正在做嵌入式 Linux 课程设计、毕业设计或者产品预研的同学也适合所有受够了串口线束缚、想给板子提升远程管理能力的开发者。这个任务本身并不需要高深的理论但细节极多稍不注意就会在某个 configure 参数上卡半天。接下来我会把整个移植链路拆开从为什么做、怎么做到踩过的坑和排查思路一步一步讲清楚。1. 为什么非要在开发板上跑 OpenSSH1.1 从串口到网络嵌入式调试的刚需串口是嵌入式开发最底层的调试手段U-Boot 引导、内核打印、早期根文件系统启动都离不开它。但真到了日常开发调试阶段串口的瓶颈非常明显物理线缆长度有限板子只能放在调试台附近串口工具一次只能连接一个终端想同时看板子日志和主机日志就得开两个窗口来回切传文件更是麻烦要么 SD 卡拷贝要么先搭个 TFTP 服务器再下载。网络调试完全不同。板子接入局域网之后你可以从办公室任意一台电脑 SSH 登上去远程执行 make、远程启动应用程序、远程调试脚本甚至用 scp 直接把交叉编译好的二进制拖到板子上。那感觉就像终于把窝在角落里的一台小机器纳入了整个开发体系里。我之前带过的一个综合项目开发板上跑着采集程序需要长期监测数据。程序在实验室开机运行人根本不可能二十四小时守在旁边。后来给板子移植了 OpenSSH所有巡检、日志抓取、参数调整全部远程完成遇到程序崩溃也能第一时间登录上去查状态。这就是移植 SSH 最朴素也最刚性的需求它把“人围着板子转”变成了“板子随时等人登录”。1.2 方案选型为什么是 OpenSSH 而不是 dropbear很多人的第一反应是BusyBox 里不是自带 dropbear 吗直接打开不就行了。dropbear 确实是一个非常轻量的 SSH 服务端实现静态编译后的二进制只有几百 KB内存占用也小非常适合 Flash 和内存资源极度受限的路由器、IoT 设备。但它也有明显的短板功能裁剪较多SCP、SFTP、密钥代理等高级特性支持不完整与某些企业级 SSH 客户端的兼容性偶尔会出问题排错手段也有限。FS4412 这类开发板内存普遍在 512MB 到 1GBFlash 或 SD 卡容量也足够压根不需要为了几十 KB 的体积牺牲功能。OpenSSH 是 SSH 协议的官方参考实现和主机端 OpenSSH 客户端天然同源兼容性最好支持完整的公钥认证、密钥代理转发、SCP/SFTP、端口转发而且因为它和 Linux 服务器上的 sshd 行为一致你在板子上遇到的所有问题都能用网上海量的“Linux SSH 排查经验”来对照。既然硬件条件允许我通常会直接选 OpenSSH省去后面迁来迁去的时间。1.3 移植整体思路先编译依赖再编译本体OpenSSH 不是一个孤立的软件它依赖两条关键链路底层加密由 OpenSSL 提供传输压缩由 zlib 负责。所以整个移植要做的事情就是交叉编译三件套先编 zlib再编 OpenSSL最后编 OpenSSH。第三步的 configure 会去自动检测前两步的头文件和库文件因此前两步的安装目录、库文件格式必须干净可靠。目标安装路径建议统一规划成/usr/local/ssh这样所有 OpenSSH 相关的可执行文件、配置文件、密钥文件都集中在一处后续打包进根文件系统时也方便管理。基于这套路径OpenSSH 的默认配置目录会是/usr/local/ssh/etc/ssh启动时它会自动到这个目录找sshd_config和主机密钥。这条依赖链其实是一个很经典的“交叉编译供应链”案例只要学会了这一套以后移植其他依赖 OpenSSL 的软件比如 curl、stunnel、nginx时思路完全一致。我在实际项目中就复用这套方法移植过好几个网络组件流程没有本质区别。2. 环境准备与编译前检查2.1 开发板与交叉工具链确认先确认开发板和工具链的基本情况。FS4412 开发板的核心是 Exynos4412四个 Cortex-A9 核心板载网卡、串口、SD 卡接口运行 Linux 3.x 内核根文件系统一般是 BusyBox 构建的。做移植之前板子的 Linux 系统必须已经能正常启动网络驱动已经能工作。交叉工具链这一块要注意 ABI 匹配。我用的工具链前缀是arm-linux-gnueabihf-硬浮点 EABI如果你的根文件系统是基于软浮点工具链构建的就必须用arm-none-linux-gnueabi-那套混用会导致加载动态库时直接报 Illegal instruction 这类问题。判断方法很简单在板子上执行ldconfig -p看看/lib下库文件的格式或者用主机侧的readelf -A /path/to/toolchain/...查看工具链默认的浮点 ABI。工具链路径要加到 PATH 里同时用arm-linux-gnueabihf-gcc -v确认能正常输出版本信息。我习惯把所有下载的源码压缩包和编译中间产物放到一个独立工作目录比如/opt/ssh构建完成后整个目录可以随时删除或者打包存档不影响主机上其他环境。2.2 根文件系统与网络环境准备调试阶段强烈推荐用 NFS 挂载根文件系统。也就是说板子从 U-Boot 启动内核时把 rootfs 直接指向主机上的 NFS 共享目录。这样做的好处非常直观所有文件拷贝、配置修改都在主机上完成板子重启后立即生效不需要反复烧写 SD 卡。如果当前板子的文件系统是烧在 SD 卡里的也可以临时在 U-Boot 里换个启动参数指向 NFS。网络环境的准备同样重要。先把板子的 eth0 配一个固定 IP比如 192.168.1.100主机对应配置 192.168.1.200确保两边能互相 ping 通。这一步没做好的话后面 sshd 起来了也连不上容易误判成移植失败。常见坑板子和主机不在同一网段或者网线插的是交换机上被隔离的端口。2.3 开源组件版本选择不是越新越好版本选择是整个移植过程中最容易栽跟头的地方。很多人习惯直接下载最新版但最新版往往对老交叉工具链并不友好。我给这套环境验证过的组合如下组件推荐版本说明zlib1.2.11稳定交叉编译非常简单OpenSSL1.0.2u1.0.x 系列最后一个维护版本API 稳定OpenSSH7.1p2 或 7.4p1老工具链环境下兼容性很好为什么不用 OpenSSL 1.1.x 和 OpenSSH 8.x因为新版 OpenSSH 在编译时会调用大量较新的 glibc 特性旧版交叉工具链的 libc 头文件不完整容易报各种“未定义的结构体成员”“隐式函数声明”错误而 OpenSSL 1.1.x 对编译器的要求也更高某些 arm 汇编文件在老版本 gas 下无法汇编。与其花大量时间打补丁不如直接用验证过的组合稳定省心。这套版本组合我建议下载官网归档目录里的 tarball不要用 Git 克隆保证源码干净。3. 三件套交叉编译完整实操3.1 交叉编译 zlib最轻松的环节zlib 是三个组件里最简单的编译过程几乎不会出错。先解压源码然后执行cd /opt/ssh tar xzf zlib-1.2.11.tar.gz cd zlib-1.2.11 export CCarm-linux-gnueabihf-gcc ./configure --prefix/opt/ssh/arm-zlib make make installzlib 的 configure 脚本与 OpenSSL 不同它不会在主机上自动检测目标平台只是根据传入参数和当前环境生成 Makefile所以交叉编译时并不需要特殊的 target 参数。关键是让 CC 环境变量指向交叉编译器生成出来的 Makefile 就会用正确的编译器。编译完成后检查一下/opt/ssh/arm-zlib目录结构确认lib/libz.a、lib/libz.so以及头文件include/zlib.h都正常生成。有一个容易踩的坑不要顺手去执行make test因为交叉编译出来的测试程序是 ARM 格式的拿到 x86 主机上直接运行会报 Exec format error这是正常的不代表编译失败。3.2 交叉编译 OpenSSLconfigure 参数与常见编译错误OpenSSL 是三个组件里最考验耐心的一个。它的编译脚本分为./config和./Configure两种前者是自动检测本机环境的封装脚本交叉编译时必须绕开直接用后者指定目标平台cd /opt/ssh tar xzf openssl-1.0.2u.tar.gz cd openssl-1.0.2u ./Configure linux-armv4 --prefix/opt/ssh/arm-openssl shared no-asm make CCarm-linux-gnueabihf-gcc make install这里的几个参数每个都有讲究。linux-armv4是 OpenSSL 源码树里为 ARM 平台预置的配置目标适用于各种 ARMv4 及以上架构处理器Exynos4412 的 Cortex-A9 完全在支持范围内。shared是必须加的它决定生成动态库libcrypto.so 和 libssl.soOpenSSH 在运行时依赖这些动态库如果不需要可以考虑静态。no-asm则是老交叉工具链环境下的救命稻草不加它的话编译过程很可能在某个汇编文件上报selected processor does not support requested special purpose register这是老版本 gas 汇编器对 ARMv7 指令支持不全导致的加上这个参数后OpenSSL 会使用 C 语言的默认实现性能稍低但完全稳定。之前有人问我能不能去掉no-asm换来更高性能我的建议是在嵌入式实验环境下不值得。OpenSSL 的汇编优化能带来性能提升但开发板上的 SSH 会话通常只是命令行操作和少量文件传输瓶颈根本不在加解密上。安全、稳定、能编过这三点优先级远高于那点性能提升。编译过程中如果报错找不到头文件或者链接器找不到库检查一下工具链路径是否在 PATH 中以及make时是否真的使用了交叉编译器。编译结束后确认/opt/ssh/arm-openssl/lib下面出现了libcrypto.so.1.0.0、libssl.so.1.0.0以及对应的软链接这一步至关重要后面拷贝到根文件系统靠的就是这些动态库。3.3 交叉编译 OpenSSHhost 平台与 DESTDIR 打包OpenSSH 的编译是整条链路的高潮也是 configure 参数最多的一步cd /opt/ssh tar xzf openssh-7.1p2.tar.gz cd openssh-7.1p2 ./configure \ --hostarm-linux-gnueabihf \ --with-zlib/opt/ssh/arm-zlib \ --with-ssl-dir/opt/ssh/arm-openssl \ --disable-pam \ --disable-etc-default-login \ --prefix/usr/local/ssh make make install DESTDIR/opt/ssh/output--hostarm-linux-gnueabihf告诉 configure 当前的目标平台是 ARM它会自动把编译器切换成交叉编译器并跳过那些需要在目标机上运行的运行时检测。--with-zlib和--with-ssl-dir分别指向我们前面编译好的组件这是 OpenSSH 能正确找到依赖库的关键。如果 configure 在检测 OpenSSL 时报错可以用更显式的方式补充CPPFLAGS-I/opt/ssh/arm-openssl/include \ LDFLAGS-L/opt/ssh/arm-openssl/lib -L/opt/ssh/arm-zlib/lib \ ./configure ...--disable-pam很重要。BusyBox 根文件系统通常没有 PAM 框架如果 configure 检测到 PAM 相关路径会对后续编译和运行埋下隐患直接禁用省心。--prefix/usr/local/ssh不是用来指定安装到主机哪个目录的而是告诉 OpenSSH“将来在目标板上你要住进/usr/local/ssh这个位置”。所有硬编码的运行时路径都会基于它生成比如配置目录、sftp-server 路径、host key 路径。最后一步make install DESTDIR/opt/ssh/output是把文件装到一个临时目录里目录结构仍然对应目标板上的/usr/local/ssh。为什么不直接装到主机/usr/local/ssh因为我们需要的是一个干净的、可以整体拷贝到 rootfs 的目录而不是污染主机环境。执行完之后/opt/ssh/output/usr/local/ssh下面应该出现sbin/sshd bin/ssh bin/ssh-keygen bin/scp bin/sftp libexec/sftp-server etc/ssh/sshd_config用file命令确认产物格式file /opt/ssh/output/usr/local/ssh/sbin/sshd # 输出类似ELF 32-bit LSB executable, ARM, EABI5 ...看到 ARM 字样就说明交叉编译成功。4. 根文件系统集成与 sshd 首次启动4.1 动态库与文件拷贝清单编译产物要整体放进 rootfs。假设 rootfs 通过 NFS 挂载在主机的/srv/nfs/rootfs目录下先拷贝主程序sudo cp -a /opt/ssh/output/usr/local/ssh /srv/nfs/rootfs/usr/local/然后拷贝动态库注意一定要保留软链接sudo cp -d /opt/ssh/arm-openssl/lib/libcrypto.so* /srv/nfs/rootfs/usr/lib/ sudo cp -d /opt/ssh/arm-openssl/lib/libssl.so* /srv/nfs/rootfs/usr/lib/ sudo cp -d /opt/ssh/arm-zlib/lib/libz.so* /srv/nfs/rootfs/lib/拷贝之前最好先用 readelf 看一遍 sshd 到底依赖哪些库arm-linux-gnueabihf-readelf -d /opt/ssh/output/usr/local/ssh/sbin/sshd | grep NEEDED输出会是libcrypto.so.1.0.0、libssl.so.1.0.0、libz.so.1、libc.so.6、libutil.so.1等。其中 libc、libutil 属于 glibc 基础库rootfs 里已经有了不需要重复拷贝我们额外补的只有前面三个。这里有个容易忽略的细节拷贝动态库时有些同学只拷贝了实际库文件忘了拷贝软链接结果板子上加载时找不到libcrypto.so.1这种不带版本号的链接名。务必连软链接一起拷或者拷贝后在 rootfs 上手动补ln -s。4.2 sshd_config 与用户密码配置OpenSSH 默认安装会把一份原始sshd_config放在/usr/local/ssh/etc/ssh/下里面有大量注释。实验环境下不用那么复杂直接重写成极简配置Port 22 ListenAddress 0.0.0.0 PermitRootLogin yes PasswordAuthentication yes PubkeyAuthentication yes UseDNS no GSSAPIAuthentication no Subsystem sftp /usr/local/ssh/libexec/sftp-serverPermitRootLogin yes是实验环境下的权宜之计方便直接用 root 登录正式产品里不建议这样后面会讲到如何收紧。UseDNS no和GSSAPIAuthentication no是必须的否则每次连接都尝试反查 DNS 和 GSSAPI登录过程会卡好几秒。Subsystem sftp那一行的路径必须和实际安装路径一致否则 SFTP 功能不可用。密码认证的前提是 rootfs 里存在有效的用户数据库。BusyBox rootfs 一般已经有/etc/passwd和/etc/shadow但 root 用户可能没有密码。在板子上执行passwd root按提示输入两次密码即可。如果板子上连 passwd 命令都没有可以在主机上用openssl passwd -1生成一段密文替换进 shadow 文件对应行原理一样。4.3 host key 生成、devpts 挂载与启动验证OpenSSH 启动时必须加载主机密钥用来向客户端证明“我是这台服务器”。密钥文件不会自动生成必须先手动创建。登录到板子上执行mkdir -p /usr/local/ssh/etc/ssh /usr/local/ssh/bin/ssh-keygen -t rsa -b 2048 -f /usr/local/ssh/etc/ssh/ssh_host_rsa_key -N /usr/local/ssh/bin/ssh-keygen -t ecdsa -f /usr/local/ssh/etc/ssh/ssh_host_ecdsa_key -N -N 表示私钥密码为空。如果不加这个参数ssh-keygen 会交互式地找你输入密码在脚本化操作里会卡住。还有两个准备工作。第一创建/var/empty目录作为特权分离的工作目录mkdir -p /var/empty第二SSH 登录后分配终端需要 PTY这依赖内核的 devpts 文件系统mkdir -p /dev/pts mount -t devpts devpts /dev/pts ls /dev/pts/如果/dev/pts里面没有ptmx手动补一个设备节点mknod /dev/ptmx c 5 2 chmod 666 /dev/ptmx这些命令每次重启都会丢失后面我会把它们整合进启动脚本。现在启动 sshd注意必须用绝对路径/usr/local/ssh/sbin/sshd很多人第一次启动时报sshd re-exec requires execution with an absolute path就是因为用了相对路径或者从某个目录里直接执行。绝对路径启动后用ps或netstat验证ps | grep sshd netstat -tlnp | grep 22看到 sshd 在监听 22 端口基本就成了。回到主机上执行ssh root192.168.1.100第一次连接会出现 host key 确认提示输入 yes再输入密码看到 shell 提示符的那一刻整个移植就算成功了。5. 常见问题排查与实战经验5.1 启动失败类动态库、绝对路径、配置文件如果 sshd 进程起不来或者一启动就退出先不要慌按顺序排查。第一种典型报错是error while loading shared libraries: libcrypto.so.1.0.0: cannot open shared object file。这说明动态库没找到。回到板子上执行ls /usr/lib/libcrypto* /lib/libz*确认库文件存在再确认软链接完整。如果库在/usr/lib但系统缓存不到可以执行ldconfig刷新BusyBox 环境如果没集成 ldconfig 命令就只能靠把库放到标准路径并确保软链接正确。第二种典型报错是启动时提示sshd re-exec requires execution with an absolute path解决方法就是绝对路径启动。另外如果配置文件本身写错了sshd 可能直接退出先用语法检查模式验证/usr/local/ssh/sbin/sshd -t-t会告诉你配置文件第几行有问题比瞎猜效率高得多。如果日志提示Missing privilege separation directory: /var/empty就是UsePrivilegeSeparation开着的但/var/empty不存在要么创建目录要么在配置里临时改成UsePrivilegeSeparation no。5.2 连接认证类host key、密码验证、权限客户端报Connection closed by 192.168.1.100这类问题最容易让人摸不着头脑因为它没有明确告诉你服务器端发生了什么。最佳做法是让 sshd 带着调试信息在前台跑/usr/local/ssh/sbin/sshd -d -E /tmp/sshd.log然后从主机再连一次把日志打出来看。最常见的两种情况一是 host key 没生成或者路径不对日志里会写Could not load host key二是密钥文件权限有问题比如别的用户能读写。host key 解决方法就是执行前面说的ssh-keygen生成命令权限问题则要确保/usr/local/ssh/etc/ssh/目录归 root 所有私钥文件权限是 600。密码正确但登录时提示Permission denied, please try again检查配置里PermitRootLogin yes是否生效以及 root 在/etc/shadow里的密码是否真的设置了。如果sshd_config里写了UsePAM yes而系统又没有 PAM登录也会异常所以前面编译时加--disable-pam在这时候就显得很重要。登录成功后如果打开终端报PTY allocation request failed on channel 0几乎可以断定是 devpts 没挂载。按 4.3 节的方法重新挂载问题就消失了。5.3 运维加固与后续扩展从能用变好用SSH 能用之后还有一堆可以提升体验和安全性的操作。首先是公钥免密登录。把主机上的公钥追加到板子的/root/.ssh/authorized_keysmkdir -p /root/.ssh chmod 700 /root/.ssh echo ssh-rsa AAAA... /root/.ssh/authorized_keys chmod 600 /root/.ssh/authorized_keys然后把sshd_config里的PasswordAuthentication改成 no从此只认密钥调试时再也不用输入密码也更安全。其次是开机自启。把必要命令写进/etc/init.d/rcSifconfig eth0 192.168.1.100 up mkdir -p /dev/pts mount -t devpts devpts /dev/pts mkdir -p /var/empty /usr/local/ssh/sbin/sshd这样板子一开机就接入网络并启动 SSH真正实现了开箱即连。如果将来要把这套方案用到产品环境还需要做几件事关闭 root 远程登录并创建普通用户把 SSH 端口从 22 改成高位端口在防火墙或 iptables 里限制 SSH 访问来源把关键文件的权限收紧。这些操作和普通 Linux 服务器的 SSH 加固思路完全一致对着文档做即可。最后分享一个小技巧如果开发板空间紧张可以只保留 sshd、sshd_config、host key、库文件把 ssh、scp、sftp 等客户端组件全部删掉服务端功能不受影响。反之如果你需要在板子上主动连接其他服务器就保留ssh和scp它们也依赖同一套库。按需裁剪能挤出不少空间。我在实际移植过程中踩过最深的坑是在 OpenSSL 的 Configure 上犹豫太久。第一次做的时候不知道要用./Configure而不是./config也不知道要加shared编出来的 OpenSSL 是纯静态库OpenSSH 链接时报了一堆奇怪错误。后来我总结出的经验是交叉编译不怕报错怕的是不看日志盲试。只要把错误信息逐行读完再对照 configure 的帮助文档大多数问题都能在二十分钟内解决。这套流程跑通之后你会发现它不仅适用于 FS4412也适用于任何基于 ARM 的 Linux 开发板。NFS rootfs、交叉工具链、zlib、OpenSSL、OpenSSH 五者之间相互配合的套路一旦熟练移植其他网络服务也只是一天之内的事情。希望这篇记录能让你少走一些弯路把更多时间花在真正有意思的嵌入式开发上。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑