Vagrant Cheatsheet - VM Init, Up, SSH & Provisioning
Vagrant reduces to one promise: write how the environment is built into a Vagrantfile, and vagrant up reproduces the same machine on anyone laptop. The lifecycle commands are not the hard part. What actually breaks are three things: pinning the box version, choosing a synced folder type, and understanding exactly when provision scripts run. This table groups those configuration points alongside the lifecycle commands, covering box management, Vagrantfile settings, networking and synced folders, multi-machine definitions, and snapshots. Reach for it when inheriting a Vagrantfile that will not boot, when sharing an environment with a new teammate, when Windows file watching makes the default shared folder painfully slow, or when you need several machines up together for integration work. The test of a good definition is destructiveness: if destroy followed by up reproduces an equivalent machine, the setup is genuinely portable rather than accidentally working.
Typical Use Case
For teams that need a multi-machine environment on one laptop and want every member to reach the same system with a single command: a local LAMP stack, a multi-node load-balancing rehearsal, or a CI job needing a service dependency. The machine and its provisioning scripts both live in a reviewable Vagrantfile, so the key is four state lines: VM lifecycle, box management, networking and synced folders, and provisioning on up and reload. The command to fear is destroy.
VM Lifecycle 9
vagrant init ubuntu/jammy64vagrant upvagrant sshvagrant haltvagrant destroyvagrant suspend / vagrant resumevagrant reloadvagrant statusvagrant global-statusBox Management 6
vagrant box add ubuntu/jammy64vagrant box listvagrant box outdatedvagrant box update --box ubuntu/jammy64vagrant box remove ubuntu/jammy64vagrant box add my-box ./package.boxVagrantfile 6
config.vm.box = "ubuntu/jammy64"config.vm.hostname = "dev-server"config.vm.provider "virtualbox" do |vb|\n vb.memory = "2048"\n vb.cpus = 2\nendconfig.vm.synced_folder "./src", "/var/www"config.vm.provision "shell", path: "setup.sh"config.vm.provision "shell", inline: "apt-get update"Network & Sync 6
config.vm.network "forwarded_port", guest: 80, host: 8080config.vm.network "private_network", ip: "192.168.33.10"config.vm.network "public_network"config.vm.synced_folder "./src", "/var/www", type: "nfs"config.vm.synced_folder "./data", "/data", disabled: truevagrant portMulti-Machine & Provision 6
config.vm.define "web" do |web|\n web.vm.box = "ubuntu/jammy64"\nendconfig.vm.define "db" do |db|\n db.vm.box = "ubuntu/jammy64"\nendvagrant up webvagrant ssh webvagrant provisionvagrant provision --provision-with shellSnapshots & Plugins 7
vagrant snapshot save my-snapshotvagrant snapshot restore my-snapshotvagrant snapshot listvagrant snapshot delete my-snapshotvagrant plugin install vagrant-vbguestvagrant plugin listvagrant package --output my-box.boxParameter matrix
| Parameter | Effect | Example |
|---|---|---|
vagrant init ubuntu/jammy64 | 在当前目录生成一份可用的 Vagrantfile,是所有后续命令的前提 | vagrant init ubuntu/jammy64 |
vagrant up | 创建并启动虚拟机;首次会下载 box 并执行 provision,之后每次启动都会重新跑 provision | vagrant up |
vagrant ssh | 用 vagrant 账号登录虚拟机,省去记用户名与密码 | vagrant ssh |
vagrant halt | 正常关机,磁盘与配置保留;这是「暂停一天」该用的命令 | vagrant halt |
vagrant destroy | 销毁虚拟机与其磁盘;不可撤销,Vagrantfile 保留但要重新下载与 provision | vagrant destroy |
vagrant suspend / vagrant resume | 把虚拟机内存快照落盘后挂起,恢复时状态与挂起前完全一致,比 halt 更快但占磁盘 | vagrant suspend |
vagrant reload | 重启虚拟机并重新执行 provision,是「改了 provision 脚本」后的标准动作 | vagrant reload |
vagrant status | 查看当前项目下每台机器的状态(running / poweroff / not created) | vagrant status |
vagrant global-status | 列出目录下所有项目的虚拟机状态,解决「我是不是在别的目录操作」的困惑 | vagrant global-status |
vagrant box add ubuntu/jammy64 | 把 box 下载到本地缓存,之后其它项目用同一个 box 就不用再下 | vagrant box add ubuntu/jammy64 |
vagrant box list | 列出本地已缓存的 box 与版本,能解释为什么版本对不上 | vagrant box list |
vagrant box outdated | 检查已装 box 是否有新版本,是升级前的标准检查 | vagrant box outdated |
vagrant box remove ubuntu/jammy64 | 移除本地缓存的 box;报错时先确认没有虚拟机仍在使用它 | vagrant box remove ubuntu/jammy64 |
config.vm.box | 指定使用哪个 box;版本锁定写在这里,改它需要 destroy 后重建才生效 | config.vm.box = "ubuntu/jammy64" |
config.vm.hostname | 设置虚拟机内主机名,排障时用于确认连的是哪台 | config.vm.hostname = "dev-server" |
vb.memory / vb.cpus | 在 provider 块里调整内存与 CPU;改后必须 reload 才生效 | config.vm.provider "virtualbox" do |vb|\n vb.memory = "2048"\n vb.cpus = 2\nend |
config.vm.synced_folder "./src", "/var/www" | 把宿主机目录挂进虚拟机;默认类型是 VirtualBox 共享文件夹,性能差时改 nfs | config.vm.synced_folder "./src", "/var/www" |
type: "nfs" | 同步目录改用 NFS,在 Linux 宿主机上性能明显好于共享文件夹 | config.vm.synced_folder "./src", "/var/www", type: "nfs" |
disabled: true | 默认不挂载该目录,需要时再用 vagrant up --enable-... 打开 | config.vm.synced_folder "./data", "/data", disabled: true |
config.vm.provision "shell", path: "setup.sh" | 引用外部脚本做初始化,脚本逻辑复杂时比 inline 更可维护 | config.vm.provision "shell", path: "setup.sh" |
config.vm.provision "shell", inline: "apt-get update" | 直接内联一段命令,适合一两行的轻量初始化 | config.vm.provision "shell", inline: "apt-get update" |
forwarded_port | 把宿主机端口映射到虚拟机端口,是本地访问容器内服务的标准做法 | config.vm.network "forwarded_port", guest: 80, host: 8080 |
private_network, ip: "192.168.33.10" | 私有网络固定 IP,多机互相访问与文档化地址都依赖它 | config.vm.network "private_network", ip: "192.168.33.10" |
vagrant port | 查映射端口的实际分配值;自动分配或被占用时会与配置不同 | vagrant port |
config.vm.define "web" / "db" | 定义多台机器,之后可以只操作其中一台 | config.vm.define "web" do |web|\n web.vm.box = "ubuntu/jammy64"\nend |
vagrant up web | 只启动具名的那一台,多机项目里避免全部拉起来 | vagrant up web |
vagrant ssh web | 登录指定机器;多机项目里不加名字会登错 | vagrant ssh web |
vagrant provision | 不重启直接重跑 provision 脚本,是改完 setup.sh 后的正确做法 | vagrant provision |
vagrant provision --provision-with shell | 只跑 shell 类 provision,跳过 chef/puppet 等其它 provisioner | vagrant provision --provision-with shell |
vagrant snapshot save / restore / list / delete | 快照是比 box 更细粒度的回滚点,装完依赖后存一个能省大量重装时间 | vagrant snapshot save my-snapshot |
vagrant plugin install | 安装 Vagrant 插件;provider 支持(virtualbox / libvirt)也靠插件提供 | vagrant plugin install vagrant-vbguest |
vagrant plugin list | 确认已装插件,排查 provider 不可用时先看这里 | vagrant plugin list |
vagrant package --output my-box.box | 把当前虚拟机打包成 box 供团队复用,等于团队的自定义基础镜像 | vagrant package --output my-box.box |
Common pitfalls
Symptomvagrant up 报找不到 box,或用的 box 版本与预期不符。
CauseVagrantfile 里写的是浮动版本或短名,本地缓存的却是另一个版本,两者不匹配。
Fix用 vagrant box list 看本地实际版本,再把 Vagrantfile 锁到该精确版本;需要时先 vagrant box add 补齐。
Symptomvagrant destroy 后再 vagrant up,耗时极长且装好的东西全没了。
Causedestroy 销毁的是虚拟机磁盘,provision 的一切都不保留,只有 Vagrantfile 还在。
Fix在装完依赖后执行 vagrant snapshot save my-snapshot,日后用 vagrant snapshot restore 回滚,而不是重装。
Symptom改了 setup.sh 里的命令,重新 vagrant up 却没有生效。
Causeup 只是启动已存在的机器,provision 脚本内容不会因文件变化而自动重跑(即使重跑也依赖脚本自身幂等)。
Fix改完脚本执行 vagrant provision 或 vagrant reload;并让脚本自身可重复执行(用 apt 的 state=present 思路而非裸安装)。
Symptom宿主机能 ping 通私有 IP,但虚拟机里连不上对方。
Cause配置了 private_network 却没指定 ip 时地址不确定;宿主机防火墙与 Vagrant 允许的网段也可能不一致。
Fix为每台机器固定 ip,并确认宿主机防火墙放行了 192.168.33.0/24。
Symptom同步目录在虚拟机里是空的,或者性能极卡。
Cause宿主机路径写错、路径含中文/空格导致挂载失败;默认的共享文件夹在部分场景下 I/O 非常慢。
Fix在虚拟机里 mount 检查挂载是否真的成功;Linux 宿主机上把 type 改成 "nfs"。
Symptom端口映射后宿主机访问不通,报 connection refused。
Cause服务只监听了 127.0.0.1 而不是 0.0.0.0,端口转发进来的连接因此被拒;或端口已被占用。
Fix让服务监听 0.0.0.0,并用 vagrant port 核对实际分配到的宿主端口。
Symptomvagrant box remove 报 box 仍在使用中。
Cause有虚拟机仍在以该 box 创建,Vagrant 拒绝删除正在被引用的 box。
Fix先 vagrant status 确认相关项目,把对应虚拟机 destroy 掉再移除 box。
Symptom多机项目里 `vagrant ssh` 总是登进同一台,停错了机器。
Cause未指定机器名时 Vagrant 使用 Vagrantfile 里第一个 define 的机器。
Fix始终显式写机器名(vagrant ssh web),并用 vagrant status 核对每台的当前状态。
Troubleshooting
1看当前目录下每台机器的状态
vagrant status区分 not created / poweroff / running,再决定该 up 还是 reload。
2看所有项目的机器状态
vagrant global-status怀疑自己在别的目录操作时用它定位。
3核对本地缓存的 box 与版本
vagrant box list版本错配是启动失败的第一嫌疑。
4检查是否有 box 可升级
vagrant box outdated升级前先备份好 Vagrantfile 与 provision 脚本。
5确认已装插件与 provider 支持
vagrant plugin listprovider 不可用时先确认插件是否装上。
6查端口实际分配值
vagrant port与 Vagrantfile 里写的 host 端口不一致时,说明发生了自动改分配。
Command Examples
Bring up a dev box with a forwarded port
vagrant init ubuntu/jammy64
vagrant box add ubuntu/jammy64
vagrant up
vagrant port
vagrant sshvagrant init only writes the Vagrantfile; it does not download the image, so run vagrant box add explicitly. Vagrant may fetch it automatically when synced folders are configured, but adding it first avoids surprises. vagrant port tells you the mapping that actually took effect: when 8080 is already taken, VirtualBox silently shifts to the next port, so never assume the number in your config file.
Output
==> web: 80 (guest) => 8080 (host) ==> default: Running (virtualbox)
Provision is the idempotent entry point; re-run it while debugging
vagrant provision
vagrant provision --provision-with shell
vagrant reloadAfter editing setup.sh there is no need to destroy and up: vagrant provision re-runs the script and saves minutes of rebuild time. Shell provisions must be idempotent on their own — apt-get update always runs, and an unguarded >> appends the config a second time — because Vagrant only guarantees the script runs once, not that it is safe to run twice.
Snapshot before any destructive operation
vagrant status
vagrant snapshot save my-snapshot
vagrant snapshot list
vagrant snapshot restore my-snapshotSave a snapshot before destroy: recovery then means vagrant snapshot restore my-snapshot instead of starting over with a fresh vagrant init, up, and a full provision run. Snapshots live in the .vagrant directory, so make sure no cleanup script removes them — they can be copied along with the project directory.
Multi-machine: define them, then bring up a specific one
vagrant status
vagrant up web
vagrant ssh web
vagrant global-statusTwo config.vm.define blocks live in the same Vagrantfile, and a bare vagrant up starts every machine, doubling memory and port usage. Always name the machine explicitly when you only need the web box. vagrant global-status shows every VM across every project on the host, which makes it the first place to look when a box "is up but unreachable".
Output
==> web: machine => web ==> db: machine => db
Drop the default synced folder in favour of a fixed-IP direct route
config.vm.synced_folder "./data", "/data", disabled: true
config.vm.network "private_network", ip: "192.168.33.10"
vagrant reloadShared folders provided by the hypervisor are far slower than native host IO for build-heavy work. The common pattern is disabled: true on the default /vagrant mount plus a private_network fixed IP, so the host reads and writes the guest directory directly. A vagrant reload is required for the network change to take effect.
Common Pitfalls
- vagrant destroy cannot be undone: the virtual disk, everything provisioned, databases, and keys inside are gone. Source survives if the default synced_folder mount exists, but apt packages, database files, and manually created users inside the VM are destroyed with it. Always vagrant snapshot save first, or vagrant package --output backup.box to keep a copy.
- vagrant halt only powers the machine off (state: poweroff) while vagrant destroy deletes it. Both make the box "disappear", but halt can be undone with vagrant up and keeps its data. When someone says they "shut it down", confirm they are not about to run destroy.
- A synced_folder mounts the entire host project directory read-write inside the VM. Any code running there, including postinstall scripts of dependencies or a Makefile target, can rewrite your host sources. On untrusted environments or unknown projects, think hard about that mount direction before starting.
- A forwarded_port whose host port is already taken does not error; VirtualBox silently moves to the next free port and vagrant up still reports success. A CI script hardcoding http://localhost:8080 then talks to the wrong thing or nothing. Read the real mapping with vagrant port instead of hardcoding it.
- vagrant box remove deletes the global box cache (by default under ~/.vagrant.d/boxes). Removing a shared team image means every machine re-downloads hundreds of megabytes to several gigabytes on the next vagrant up, which simply hangs offline. Check vagrant box list and tell the team first.
- vagrant package captures the full current state, including all data, tokens, .env files, and private keys (unattended VirtualBox generates authorized_keys inside the machine). Never upload the resulting .box to a public location or commit it; strip sensitive data first.
Tips
- vagrant up downloads the box on first run; later starts are fast.
- Vagrantfile is Ruby, but only basic config is needed.
- vagrant-vbguest auto-updates VirtualBox Guest Additions.
- snapshot save/restore quickly persists/restores VM state.
- NFS sync outperforms the default VBox shared folder for big projects.
- vagrant package bundles a configured VM into a box for sharing.
FAQ
Should I reload or destroy the VM after installing new dependencies?
Prefer vagrant reload: it restarts the machine and re-reads the Vagrantfile while keeping the data on disk. To re-run provisioning scripts, use vagrant provision, or scope it to one provisioner with --provision-with shell. vagrant suspend and vagrant resume are the fastest pair for closing the laptop and picking work back up. vagrant destroy wipes the machine and every change in it, so reserve it for deliberate clean slates. For a read-only check use vagrant status, or vagrant global-status to see every Vagrant environment on the machine at once.
Why is a prepared VM so much faster than the base box, and what does it cost me?
The first vagrant up downloads the box image and runs a full provision pass that installs dependencies and initialises the machine; every later boot reuses that on-disk state and is ready in seconds. The cost is a slow first run plus a locally dirty environment: after editing a template you must reload or re-provision manually. When repeated rebuilds get expensive, store a clean baseline with vagrant snapshot save my-snapshot and return to it any time via vagrant snapshot restore my-snapshot. Review them with vagrant snapshot list and delete the ones you no longer need.
How do I define multiple machines (web and db) in the Vagrantfile?
Name each machine with config.vm.define: config.vm.define "web" do |web| web.vm.box = "ubuntu/jammy64" end and config.vm.define "db" do |db| db.vm.box = "ubuntu/jammy64" end. Then vagrant up web boots just that machine and vagrant ssh web logs into it, while omitting the name starts everything. Cross-machine access is handled by the network config: config.vm.network "forwarded_port", guest: 80, host: 8080 publishes a guest port on the host, and vagrant port shows the active mapping. For a stable address use config.vm.network "private_network", ip: "192.168.33.10".
Installing dependencies over the shared folder is painfully slow — what about NFS?
The default VirtualBox shared folder performs badly with many small files, exactly what npm install and pip install generate. Switching with config.vm.synced_folder "./src", "/var/www", type: "nfs" routes traffic through NFS and is typically far quicker. Trim the surface with config.vm.synced_folder "./data", "/data", disabled: true so large trees are not mounted at all. Size the machine itself in the same config.vm.provider "virtualbox" block: vb.memory = "2048" and vb.cpus = 2, so the VM has enough headroom before you install anything. You can also run vagrant plugin install vagrant-vbguest to keep Guest Additions current.
How do I hand my tuned VM to the team instead of making everyone reinstall?
Export it: vagrant package --output my-box.box bundles the current VM into a box file, and a teammate installs it locally with vagrant box add my-box ./package.box before pointing their project at it. Tidy your box inventory first with vagrant box list, check vagrant box outdated for newer versions, refresh one with vagrant box update --box ubuntu/jammy64, and reclaim space with vagrant box remove for anything unused. Keep the Vagrantfile and provision scripts under version control as the source of truth — the packaged box is a snapshot of the environment, and both together are what guarantee your colleague gets the same setup.
Official References
Each command links to its official documentation below, so you can verify the latest usage and read deeper.
Maintained by LaoHand
Publicly updated on Jul 21, 2026, continuously proofread against official docs.
Contact Us
Wrong command or description? Send us corrections, business inquiries or product feedback by email.
Contact Us