Ubuntu共享文件夹:VMware/VirtualBox/CIFS挂载排错
2026/9/18 3:08:58 网站建设 项目流程

前阵子帮同事配一台 Ubuntu 开发机,他的诉求很朴素:Windows 主机上有一堆资料和代码,想直接在 Ubuntu 虚拟机里读写,不想每次都插 U 盘、也不想来回复制粘贴。我到了才发现,他折腾了整整一个下午,/mnt/hgfs目录是空的,改了三遍fstab,重启之后虚拟机直接卡在启动阶段进不去系统。这类问题其实一点都不难,难的是没人把"为什么要这么做"讲清楚,导致每次遇到报错只能靠搜。这篇就把虚拟机中 Ubuntu 与主机共享文件夹这件事从头到尾捋一遍——VMware 和 VirtualBox 两条主流路线怎么走、走不通时怎么换成网络挂载、开机自动挂载为什么会失效、权限和编码这些反复咬人的细节怎么处理,以及哪些目录打死都不能放进共享文件夹。不管你是刚装好虚拟机的新手,还是已经被fstab坑过一次的老手,应该都能在这里找到自己缺的那一块。

1. 共享文件夹不是"拖拽"的替代品,先把这笔账算清楚

1.1 把文件送进虚拟机,一共有四条路

很多人一上手就想着配共享文件夹,但其实在虚拟化环境里搬运文件,至少有四种方式,各自适用的场景完全不同。

第一种是拖拽和剪贴板共享。装了open-vm-tools-desktop或者 VirtualBox 的增强功能包之后,主机和虚拟机之间可以互相拖文件、复制文本。这个方式胜在零配置,临时传个 PDF、复制一段命令非常方便。但它的短板也很明显:大文件慢得离谱,文件夹拖拽经常丢文件,而且没有稳定的路径——虚拟机里的程序没法引用"我刚拖进来的那个文件"。它适合人,不适合程序。

第二种是网络传输,也就是scpsftprsync或者直接开个 Samba 服务。这种方式最通用,跨宿主机的方案都一样,网速也稳。缺点是每次都要敲命令或者开客户端,对于"我要持续在某个目录里写代码"这种高频场景,手感不连贯。

第三种是虚拟化平台自带的共享文件夹,VMware 叫 Shared Folders(底层是 HGFS 协议),VirtualBox 叫 Shared Folders(底层是 vboxsf 驱动)。配置好之后,主机的一个目录会以挂载点的形式出现在 Ubuntu 里,像本地目录一样cd进去就能用。这是最贴近"无缝"的方案,也是这篇要重点讲的。

第四种是版本库或者网盘。代码走 Git,资料走内网同步盘,本质上是用一个中间层解耦。多人协作、需要版本回溯的场景这才是正解,但单机开发时它就是绕远路。

1.2 共享文件夹真正的价值在哪

我个人的判断标准很简单:如果一个目录我一天要进出十次以上,就值得配共享文件夹;否则不如用scp

举个具体的例子。我在 Ubuntu 里跑 Zephyr 的编译环境,但代码编辑器还是习惯用主机上的 VS Code。这种情况下共享文件夹几乎是唯一解——主机侧编辑、虚拟机侧编译,一套代码两个系统共用。反过来,如果只是偶尔从主机拷一个gcc安装包进去,那scp一句话就完事了,配共享文件夹纯属浪费时间。

还有一个容易被忽略的点:共享文件夹是双向的。你在 Ubuntu 里新建、删除、改名的文件,主机上同步可见。这意味着你可以把它当成一个跨系统的"中转站",而不是单向的导入通道。

不过这里要先打一剂预防针。共享文件夹的性能、权限模型、文件锁机制和本地磁盘都不一样,它不适合承载编译产物、数据库文件、依赖目录。这个结论后面第 8 章会展开讲,现在只要记住一句话:共享文件夹适合放"源码和文档",不适合放"构建产物和运行时数据"。

2. VMware 路线:open-vm-tools 到 /mnt/hgfs 的完整落地

2.1 宿主机侧:设置面板里的三个关键开关

VMware 的共享文件夹配置全在虚拟机设置里。关闭虚拟机(或者至少确认不是挂起状态),打开虚拟机设置 → 选项 → 共享文件夹,这里有三档:已禁用、始终启用、在下次关机或挂起前启用

我一般直接选始终启用。选"下次关机前启用"的话,重开虚拟机之后共享就没了,很多人第一次踩坑就是踩在这里——明明昨天下班前还好好的,今天开机/mnt/hgfs就空了。

然后点"添加",填三个东西:

  • 主机路径:主机上你要共享的目录,建议选一个路径里没有空格、没有中文的目录。中文路径在老版本的 vmhgfs 驱动上会出现挂载后乱码甚至挂载失败的情况。
  • 名称:共享名,这是虚拟机里看到的标识符,建议用小写英文加下划线,比如share_code
  • 启用此共享:勾上。"只读"按需勾,如果你的目的是在虚拟机里写文件,记得别勾只读。

注意:改完共享文件夹设置之后,如果虚拟机正在运行,guest 侧的挂载点不会自动刷新。要么重启虚拟机,要么手动重新挂载一次,别以为是配置没生效。

2.2 客户机侧:为什么装 open-vm-tools 而不是官方安装包

Ubuntu 上装 VMware Tools 有两条路:从 VMware 菜单里点"安装 VMware Tools"挂载虚拟光驱,然后手动解压、跑vmware-install.pl;或者直接aptopen-vm-tools

我强烈建议走第二条,而且只用第二条。

sudo apt update sudo apt install -y open-vm-tools open-vm-tools-desktop

理由有三个。第一,open-vm-tools是 Ubuntu 官方仓库维护的版本,和内核版本是配套的,内核升级之后不会出现驱动编译失败、模块加载不上的问题。第二,官方那个vmware-install.pl装出来的驱动是编译到内核的,每次apt upgrade换内核,你的共享文件夹就大概率挂掉,还得重新跑一遍安装脚本。第三,open-vm-tools-desktop这个包负责分辨率自适应、剪贴板共享、拖拽,少了它你会发现屏幕只有 800x600,而且剪贴板不通。

装完之后确认服务在跑:

systemctl status open-vm-tools

正常应该显示active (running)。如果是inactive或者failed,先看一眼它为什么起不来,别急着去搞挂载——驱动层没起来,后面全是空谈。

2.3 手动挂载一次,把参数彻底摸清楚

工具装好了,先别急着写fstab第一步是手动挂载成功,确认路径和参数都对,这一步能帮你排掉九成的后续问题。

先确认虚拟机能不能看到你在设置里加的那个共享:

vmware-hgfsclient

这条命令会列出所有可用的共享文件夹名称。如果它输出了你配的那几个名字,说明驱动层是通的;如果什么都不输出,那问题在 VMware 配置或者 open-vm-tools,不在挂载。

然后创建挂载点并挂载:

sudo mkdir -p /mnt/hgfs/share_code sudo /usr/bin/vmhgfs-fuse .host:/share_code /mnt/hgfs/share_code \ -o subtype=vmhgfs-fuse,allow_other,uid=1000,gid=1000

这里的参数值得逐个解释:

  • .host:/share_code是 HGFS 协议的特殊路径,.host:代表主机侧根目录,后面跟共享名。
  • subtype=vmhgfs-fuse让内核知道这是 fuse 类型的 vmhgfs 文件系统。
  • allow_other允许非 root 用户访问挂载点。不加这个参数,普通用户cd进去会得到Permission denied,这个坑极其常见。
  • uid=1000,gid=1000把挂载点里的所有文件都映射成你的普通用户身份。你的 uid 用id -u确认一下,第一个普通用户通常是 1000。

想一次性挂载所有共享,把源写成.host:/就行:

sudo /usr/bin/vmhgfs-fuse .host:/ /mnt/hgfs -o subtype=vmhgfs-fuse,allow_other

挂载完ls /mnt/hgfs/share_code,能看到主机上的文件就成了。

2.4 /mnt/hgfs 是空的,按这个顺序查

这是被问得最多的一个问题。排查顺序我总结成一条链,从上往下走,别跳步:

  1. 先跑vmware-hgfsclient。没输出 → 回到虚拟机设置检查"共享文件夹是否启用"、共享是否勾选、虚拟机是否需要重启。
  2. 有输出但还是空→ 检查/mnt/hgfs这个目录本身是否存在。很多时候是挂载点目录被删了,mkdir一下就好。
  3. 目录存在、挂载命令也没报错,但ls是空的→ 大概率是allow_other没加,或者你用的是普通用户去访问 root 挂的东西。
  4. fuse: device not found或类似错误→ fuse 相关组件缺失,sudo apt install fuse3补上。
  5. 挂载命令直接说找不到vmhgfs-fuseopen-vm-tools没装好,回到 2.2 重新装。

最后再提醒一个细节:如果你曾经手动装过官方 VMware Tools,又装了open-vm-tools,两者会打架,/usr/bin/vmhgfs-fuse可能被覆盖成旧版本。这种情况先把手动装的卸载干净再重来,比反复调试快得多。

3. VirtualBox 路线:增强功能包与 vboxsf 组的权限账

3.1 Guest Additions 的两种装法

VirtualBox 的共享文件夹依赖Guest Additions,装法和 VMware 类似,但细节不同。

第一种是图形化:启动虚拟机,菜单栏设备 → 安装增强功能,它会把一个 ISO 挂进光驱,然后在 Ubuntu 里手动执行:

sudo mkdir -p /mnt/cdrom sudo mount /dev/cdrom /mnt/cdrom cd /mnt/cdrom sudo ./VBoxLinuxAdditions.run

第二种是走仓库:

sudo apt install -y virtualbox-guest-utils virtualbox-guest-x11

两种装法的取舍,我的经验是:内核版本越新,越建议走仓库。官方 ISO 里的VBoxLinuxAdditions.run会现场编译内核模块,遇到新内核(比如 Ubuntu 24.04 的 6.8)经常报编译错误,报错信息还很难读。仓库版本跟着系统更新走,省心得多。

装完之后一定要重启虚拟机。vboxsf 是内核模块,不重启加载不上,mount -t vboxsf会直接告诉你"unknown filesystem type"。

3.2 vboxsf 用户组:九成的权限问题都出在这

VirtualBox 共享文件夹的权限模型和 VMware 完全不同,它不是靠uid参数映射,而是靠用户组

原理是这样:虚拟机里的共享挂载点属于vboxsf用户组,只有该组成员才有读写权限。所以你要做的第一件事是把自己加进去:

sudo usermod -aG vboxsf $USER

关键点:加完组必须重新登录(注销再登录,或者重启)才生效。很多人加完组之后在当前终端里试半天还是Permission denied,就是因为组的变更不会影响已经打开的会话。想确认是否生效,开一个新终端跑groups,看到列表里有vboxsf才算成功。

挂载命令是这样的:

sudo mkdir -p /mnt/share_code sudo mount -t vboxsf share_code /mnt/share_code

注意share_code是在 VirtualBox 设置里填的共享名称,不是主机上的路径。

3.3 /media/sf_xxx 自动挂载点的坑

VirtualBox 有一个很方便的设计:如果在共享文件夹设置里勾了"自动挂载",它会在/media/下自动创建一个以sf_开头的挂载点,比如sf_share_code

这个自动挂载点有两个特点需要记住:

一是它默认归属 root:vboxsf,普通用户能不能访问完全取决于你在不在vboxsf组里。所以 3.2 那一步是绕不开的。

二是它不支持自定义挂载参数。你不能给它加uidumask这些选项。如果你需要精细控制权限,比如让某个服务进程以特定身份读共享目录,那自动挂载点就不够用了,得自己在设置里取消自动挂载,改用/etc/fstab手动配置。

我的一般做法是:日常开发用自动挂载点,省事;需要跑服务或者对接 CI 的场景,手动配fstab两种模式在同一个虚拟机里共存也没问题,只是别挂同一个共享名两次。

4. 走网络的路:把主机目录用 CIFS 挂进 Ubuntu

4.1 什么时候该放弃 hgfs 和 vboxsf

平台自带的共享文件夹虽然好用,但有几种情况你必须转向网络挂载:

  • 主机是 Windows,虚拟化平台是 Hyper-V 或者干脆是另一台机器;
  • 你需要让宿主机之外的第三台设备也访问这个目录;
  • 共享文件夹的性能怎么调都不行,想换条路试试;
  • 你要在 Docker 容器里访问这个目录,而容器对 fuse 挂载点的穿透有限。

这时候 SMB/CIFS 就是标准答案。它的本质是:Windows 主机把目录共享出来,Ubuntu 作为客户端用cifs文件系统挂上去。

4.2 Windows 侧的共享设置,别漏掉账号凭证

先澄清一个概念:共享文件夹的访问靠的是"共享权限 + NTFS 权限"两套,取交集。很多人只在"共享"标签页里加了 Everyone 可读写,结果还是被拒,原因就在 NTFS 权限那一层。

操作路径:

  1. 右键目标文件夹 → 属性 →共享→ 高级共享 → 勾选"共享此文件夹" → 权限里给对应账号读写。
  2. 切到安全标签页,确认你的账号(或者 Everyone)在这也有读写权限。
  3. 记下主机在局域网里的 IP:ipconfig看 IPv4 地址。

然后强烈建议单独建一个本地账号专门用于共享,别用你的微软账号。原因很实际:微软账号登录 Windows 时,网络凭证的用户名往往要用MicrosoftAccount\你的邮箱这种格式,而在 Ubuntu 的cifs挂载参数里写这个格式容易出转义问题。用一个简单的本地账号(比如smbuser)会省掉大量麻烦。

注意:Windows 的"密码保护的共享"开关如果开着,任何访问都必须提供有效账号密码。家庭环境里如果只是自己用,可以关掉;但只要这台机器连在办公网,就别关。

4.3 cifs-utils 挂载命令的每个参数都在干什么

Ubuntu 侧先装工具:

sudo apt install -y cifs-utils

然后手动挂一次:

sudo mkdir -p /mnt/win_share sudo mount -t cifs //192.168.1.10/share_code /mnt/win_share \ -o username=smbuser,password=你的密码,uid=1000,gid=1000,iocharset=utf8,vers=3.0

参数逐个拆:

参数作用不写会怎样
username/password访问共享的凭证Windows 侧开了密码保护时直接拒绝
uid/gid把挂载文件映射成哪个本地用户文件属主是 root,普通用户改不了
iocharset=utf8指定字符集中文文件名显示成问号或方块
vers=3.0指定 SMB 协议版本可能协商失败,报Host is down
file_mode/dir_mode精细控制文件/目录权限位默认权限可能过宽或过窄
nofail挂载失败不阻塞启动见第 5 章,严重时进不去系统
_netdev声明依赖网络开机时网络还没起来就去挂,必然失败

vers这个参数单独说一句。SMB 协议有 1.0、2.0、2.1、3.0、3.1.1 好几个版本,Windows 10/11 默认禁用了 SMB 1.0。如果你的 Ubuntu 客户端默认协商到了 1.0,就会直接被服务端拒绝,报的错还特别有迷惑性——mount error(112): Host is down,看着像网络不通,其实是协议版本对不上。遇到这个报错,第一反应就是把vers=3.0加上。

4.4 密码不要写在命令行里

上面那条命令有个明显的问题:密码是明文的,而且会进 shell 历史。

正确做法是写一个凭证文件:

sudo mkdir -p /etc/samba sudo tee /etc/samba/cred_win <<'EOF' username=smbuser password=你的密码 EOF sudo chmod 600 /etc/samba/cred_win sudo chown root:root /etc/samba/cred_win

然后挂载命令简化成:

sudo mount -t cifs //192.168.1.10/share_code /mnt/win_share \ -o credentials=/etc/samba/cred_win,uid=1000,gid=1000,iocharset=utf8,vers=3.0

权限位一定要是600cifs-utils会检查凭证文件的权限,太宽松的话会直接拒绝使用并给出警告。这是有意为之的设计,别想着绕过。

4.5 "Windows 11 找不到网络路径"的几种真实原因

这个报错在热搜里出现的频率很高,实际原因就那几类:

第一类是权限和协议。Windows 11 家庭版默认关闭了"不安全的来宾登录",从 Linux 侧匿名访问会被拒。解决方向是给共享配置一个真实账号,而不是试图绕过认证。

第二类是主机防火墙。Windows 防火墙的"文件和打印机共享"入站规则如果没启用,Ubuntu 侧ping得通但mount一定失败。检查一下防火墙里的专用网络配置文件是否允许了共享。

第三类是网络发现。两台机器如果不在同一个网段,或者路由器做了 AP 隔离,那就压根连不上。虚拟机网络用 NAT 模式时,虚拟机在另一个虚拟网段里,直接访问主机 IP 也可能不通,这种情况要么改桥接模式,要么用主机的虚拟网卡地址。

第四类是浏览器缓存。Windows 里\\主机名\共享名打不开但\\192.168.1.10\共享名能打开,基本都是名称解析的问题。我的习惯是全程用 IP 地址,不做主机名解析,能省掉一大类玄学问题。

5. 开机自动挂载:fstab 写错一个参数,重启就白干

5.1 vmhgfs-fuse 的 fstab 写法

手动挂载成功之后,把它固化到/etc/fstab:

.host:/share_code /mnt/hgfs/share_code fuse.vmhgfs-fuse allow_other,defaults,uid=1000,gid=1000 0 0

几个要点:

  • 文件系统类型写fuse.vmhgfs-fuse,不能只写vmhgfs-fuse,否则mount找不到对应的挂载助手。
  • 挂载点目录必须先mkdir好,fstab不会帮你创建。
  • allow_other必须保留,原因和手动挂载一样。

改完fstab之后,先别重启,用这条命令验证:

sudo mount -a

mount -a会尝试挂载所有fstab里没挂上的条目,有语法错误会当场报出来。这一步是保命操作,一定要养成习惯。

5.2 cifs 挂载"重启后失效"的真正原因

同一条cifs挂载命令,手动执行百试百灵,写进fstab重启就挂不上——这个现象背后其实是一个非常确定的时序问题。

系统启动的时候,挂载文件系统的动作由systemd在早期阶段完成,而那会儿网络栈往往还没初始化完。cifs挂载需要跟远端建立 TCP 连接,网络没起来自然就失败。更麻烦的是,如果fstab里没有声明容错,systemd会因为"本地文件系统挂载失败"进入紧急模式,你看到的就是一个黑底白字的emergency shell,连桌面都进不去。

这就是为什么_netdevnofail这两个参数几乎是fstabcifs条目的标配:

//192.168.1.10/share_code /mnt/win_share cifs credentials=/etc/samba/cred_win,uid=1000,gid=1000,iocharset=utf8,vers=3.0,_netdev,nofail 0 0

5.3 _netdev、nofail、x-systemd.automount 到底谁救谁

这三个选项经常被混着用,但它们的职责完全不同:

  • _netdev:告诉systemd"这个挂载依赖网络",于是它会把这个挂载排到网络就绪之后再执行,而不是并行启动。它解决的是时序问题
  • nofail:告诉systemd"这个挂载失败无所谓,别卡住启动"。它解决的是容错问题
  • x-systemd.automount:把挂载改成按需触发——只有你第一次访问挂载点目录时,系统才真的去建立连接。它同时能解决时序问题和启动阻塞问题,代价是第一次访问会有一点点延迟。

我的实际配置习惯是三者搭配:

//192.168.1.10/share_code /mnt/win_share cifs credentials=/etc/samba/cred_win,uid=1000,gid=1000,iocharset=utf8,vers=3.0,_netdev,nofail,x-systemd.automount,x-systemd.idle-timeout=600 0 0

x-systemd.idle-timeout=600的意思是空闲十分钟自动断开,下次访问再重连。对不常访问的共享来说,这样能少占用一点资源,也让网络波动时的恢复更顺滑。

注意:用了x-systemd.automount之后,原来的挂载点目录会被 systemd 用一个 autofs 目录接管。这时候ls /mnt/win_share看起来是空的,别慌,cd进去就会触发真实挂载。

5.4 把虚拟机搞进不了系统之后怎么救

回到开头说的那个同事。他在fstab里写了cifs条目,没加nofail,重启之后进 emergency shell,而他又不知道 root 密码——因为 Ubuntu 默认锁了 root 账户。

救援路径是:

  1. 在 emergency shell 里输入 root 密码。如果没设过,先想办法进单用户模式。
  2. 更通用的办法是:在 GRUB 菜单里按e编辑启动项,在linux那一行末尾加上systemd.unit=rescue.targetsingle,然后Ctrl+X启动,这样可以进到一个不挂载fstab里额外条目的救援环境。
  3. 进去之后把出问题的fstab行注释掉,reboot
  4. 最省事的办法其实是:用虚拟机快照。VMware 和 VirtualBox 都支持快照,改fstab这种高风险操作之前打一个快照,出问题几十秒回滚。

这条经验我踩过一次就牢牢记住了:动/etc/fstab之前,先打快照。成本几乎为零,收益是省掉一整个下午。

6. 权限、编码、文件锁:三个反复咬人的细节

6.1 "权限不够"的三种不同含义

Permission denied这个错误在共享文件夹场景下至少对应三种不同的原因,得分开处理:

第一种是挂载参数层面的。VMware 路线下,如果你忘了allow_other,或者没写uid/gid,挂载点里的文件属主就是 root,普通用户读写全被拒。解决方式就是回到挂载命令,把参数补齐。

第二种是文件系统层面的。CIFS 挂载时,uid/gid只决定了"文件看起来属于谁",实际能不能写还取决于服务端给你的共享权限。也就是说,你在 Ubuntu 侧chmod 777是没用的——CIFS 的权限位是客户端映射出来的假象,真正说了算的是 Windows 那边的 NTFS 权限。这一点很多人理解反了,折腾半天chmod完全没效果。

第三种是换行符和可执行位。挂载点上的 shell 脚本,因为你没法在 CIFS 上真正设置可执行位(除非加file_mode=0775这类参数),./script.sh会报权限错误。解决办法是显式用bash script.sh调用,或者把脚本放到本地目录。

6.2 中文乱码和 iocharset

挂载之后文件名变成?????.txt,原因基本都是字符集没指定。

CIFS 挂载要加iocharset=utf8。较新的内核里这个参数可能被提示为已废弃,换用nls=utf8也可以,两个都写上去一般不会报错。

还有个更隐蔽的情况:文件名本身在 Windows 侧就是乱码的。Windows 用的是 UTF-16,而某些老的压缩包解压出来是 GBK 编码的文件名,这种在 Linux 侧怎么调参数都救不回来,得在 Windows 侧先重命名。

VMware 的 HGFS 和 VirtualBox 的 vboxsf 走的是自己的协议,基本不会有字符集问题。所以如果你对中文文件名有强需求,平台自带的共享文件夹会比 CIFS 更省心。

6.3 软链接、文件锁和 inotify:开发场景的三个暗雷

这三个是"配好了能用,但用着用着突然发现不对劲"的典型。

软链接:在共享文件夹里创建指向挂载点之外的符号链接,主机侧往往识别不了。CIFS 上默认软链接会被当成普通文件,需要加mfsymlinks参数。但即便加上,兼容性也只能说一般。我的建议是:项目里不要用跨边界的软链接,node_modules那种靠软链接组织的依赖目录尤其别放共享文件夹。

文件锁:数据库文件(SQLite、LevelDB)放在共享文件夹上,并发访问时锁机制会失效或者死锁,轻则报错重则数据损坏。这类文件必须放在虚拟机本地磁盘。

inotify:这是最容易被忽略、也最容易让人怀疑人生的一个。Webpack、Vite、nodemon这类工具靠 inotify 机制监听文件变化。而虚拟化平台的共享文件夹不会把主机的文件变更事件传递到 guest 侧,结果就是你在主机上改代码,Ubuntu 里的 dev server 毫无反应,手动重启才生效。

绕开的方式有几种:把源码放在虚拟机本地,主机通过 SSH 远程编辑;或者改用轮询模式(Vite 里是server.watch.usePolling: true),代价是 CPU 占用上升。我一般首选轮询,配置改一行就完事。

6.4 换行符:那个烦人的 ^M

Windows 的换行是CRLF,Linux 是LF。在共享文件夹里编辑的 shell 脚本,如果被 Windows 侧的编辑器改成了 CRLF,在 Ubuntu 里执行会报:

/bin/bash^M: bad interpreter: No such file or directory

这个^M就是\r。解决方式有三种,按推荐度排序:

  1. 从源头解决:编辑器里设置该目录的换行符为 LF,VS Code 右下角就能切,顺手再配一个.gitattributes(* text=auto eol=lf)。
  2. 事后修:sed -i 's/\r$//' script.sh或者装dos2unix
  3. 兜底:调用的时候用bash script.sh,bash\r的容忍度比内核加载 shebang 时要高一点,但这不是长久之计。

7. 反向打通:让主机和局域网直接访问虚拟机

7.1 网络模式选 NAT 还是桥接

共享文件夹是"主机到虚拟机"的方向,很多时候你还想要反方向:主机浏览器打开虚拟机里跑的服务,或者手机连虚拟机的测试接口。

这时候网络模式的选择就变得关键了:

模式虚拟机的 IP主机能否直连局域网设备能否直连适用场景
NAT虚拟网段,如 192.168.x.x需要端口转发不能只上网,不需要被访问
桥接和主机同网段需要被访问,推荐
仅主机私有网段不能纯内网调试

我的默认选择是桥接。虚拟机拿到一个和主机同网段的 IP,主机和手机都能直接访问,不用配任何端口转发,省掉一堆心智负担。

注意:桥接模式下虚拟机会暴露在局域网里,装完系统记得看一眼ufw的状态。默认 Ubuntu 桌面版的ufw是不启用的,服务端口是敞开的。

7.2 从主机 SSH 进虚拟机:四步搞定

这是使用频率最高的反向通道,配置也很简单:

sudo apt update sudo apt install -y openssh-server sudo systemctl enable --now ssh sudo systemctl status ssh

四步之后,在虚拟机的终端里跑ip addr,找到inet那一行的地址,比如192.168.1.23。回到主机开一个终端:

ssh 你的用户名@192.168.1.23

连不上的排查顺序是:ping通不通(不通就是网络模式的问题),ping通但ssh连不上就看systemctl status ssh服务在不在跑,服务在跑就看sudo ufw status防火墙拦没拦。这三步能覆盖绝大部分情况。

用 SSH 还有一个额外好处:你可以把 VS Code 的 Remote-SSH 指向虚拟机,这样源码放在虚拟机本地磁盘(避开 inotify 和性能问题),编辑体验还是主机上那套,两全其美。这个组合是我目前最推荐的开发环境方案,比共享文件夹方案更稳。

7.3 主机浏览器打开虚拟机里的服务

在 Ubuntu 里跑了一个 web 服务,监听8080:

python3 -m http.server 8080

如果网络是桥接模式,主机浏览器直接访问http://192.168.1.23:8080就能打开。

但有个坑要注意:服务监听的地址是127.0.0.1还是0.0.0.0很多开发服务器默认只监听本地回环,这种情况下外部怎么都连不上。启动时显式绑定:

python3 -m http.server 8080 --bind 0.0.0.0

Node 项目里常见的是在配置里改host: '0.0.0.0',Flask 里是app.run(host='0.0.0.0')。这几个地方的默认值都不一样,遇到连不上先往这里想。

7.4 局域网其他设备访问的注意事项

手机连虚拟机做移动端调试时,除了上面说的绑定地址,还要确认:

  • 主机和手机在同一个 Wi-Fi 下,并且路由器没开客户端隔离;
  • 虚拟机防火墙放行对应端口:sudo ufw allow 8080/tcp;
  • 如果服务用了 HTTPS 自签证书,手机上要先信任证书,否则请求会被静默拦截。

8. 性能与工程习惯:哪些目录绝对不能放共享文件夹

8.1 共享文件夹的 IO 到底慢多少

先说结论:虚拟化平台的共享文件夹,IO 性能大约是本机磁盘的十分之一到二十分之一,尤其是小文件随机读写。

原因在于数据要经过一层协议转换——VMware 走 HGFS、VirtualBox 走 vboxsf,每次文件操作都要在 guest 和 host 之间来回传消息。单个大文件的顺序读写还好,但 npm 安装那种动辄几万个小文件的操作,性能差距会被放大到难以忍受的程度。

我做过一个不太严谨的对比:在一个中型前端项目里跑npm install,放在虚拟机本地磁盘大概 40 秒,放在共享文件夹里跑了六分多钟,而且经常在中途因为文件锁冲突中断。

8.2 黑名单:这几类目录请远离共享文件夹

目录类型为什么不能放替代方案
node_modulesvenvtarget海量小文件,IO 灾难;软链接兼容性差放虚拟机本地磁盘
.git仓库对象频繁随机读写,且涉及文件锁放本地,或者只用只读拷贝
SQLite / LevelDB 等嵌入式数据库文件锁在共享文件系统上不可靠,有损坏风险绝对放本地
编译中间产物大量临时文件创建删除放本地,或指向/tmp
Docker 数据目录依赖 overlayfs 和特定内核特性放本地

8.3 我实际用的目录划分方案

踩了几轮坑之后,我现在的目录结构是这样分的,供参考:

~/work/ # 虚拟机本地磁盘,放代码仓库、依赖、构建产物 /mnt/hgfs/share/ # 共享文件夹,放设计稿、需求文档、测试数据、安装包 ~/downloads/ # 虚拟机本地,从共享目录拷进来的东西先落在这里

具体分工的逻辑是:

  • 代码本身放本地。因为 inotify、文件锁、性能这三件事,代码放共享文件夹全是减分项。
  • 资料和文档放共享。这类文件访问频率低、体积小、只需要"能打开",性能完全不敏感。
  • 大文件先拷后跑。比如一个 2GB 的数据集,先cp到本地磁盘再跑训练或者分析,比直接在共享目录上处理快得多。

同步代码用 Git,同步资料用共享文件夹,这个组合用了大半年没出过问题。

8.4 一个容易被忽略的收尾习惯

最后分享一个实际操作里的小习惯:每次改完挂载配置,把当前可用的配置命令记到虚拟机里一个固定的文本文件里,比如~/notes/mount-setup.md

理由很实际:虚拟化平台升级、内核升级、系统重装都会让共享文件夹失效,而重新排查一遍的成本远高于查一次笔记。我在 Ubuntu 系统重装之后重建环境的次数不下五次,有这份笔记每次十分钟就能恢复,没有的话就得重新翻一遍这篇文档里讲的所有内容。

同理,open-vm-toolscifs-utils这类包的安装命令也一并记上。这些东西平时记不住,但需要的时候又特别急,提前存一份比什么都强。

另外提一句硬件资源:装 Ubuntu 虚拟机的时候,内存别给太少,给到 8GB 以上、CPU 给 4 核,能省掉很多"以为是共享文件夹的问题、其实是虚拟机卡"的误判。虚拟机的资源分配不到位,再好的挂载配置也跑不起来。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询