Getting started
One-time setup on Linux, on Windows through WSL2, or on a Mac inside a small Linux VM. It takes ten to twenty minutes; longer the first time on a machine that has never had WSL2 or a VM. After this, every lab is a single command.
Quick start
The whole setup in four steps. Each one links to the detail below.
What you need
- Linux, Windows with WSL2, or a Mac on macOS 13.3 or later running a small Linux VM. Ubuntu 22.04 or 24.04 is the tested path on all three.
- 4 GB of free RAM and a few GB of disk.
- sudo access. Containerlab manages network namespaces and needs it.
Install
Three tracks. Pick the one that matches the machine in front of you. All three end up at the same place: a Linux shell with Docker and Containerlab on it.
Docker Desktop is not required on any track. Containerlab starts FRR as a plain container from the command line.
Linux
Ubuntu 22.04 or 24.04 is the tested path.
-
Docker
curl -fsSL https://get.docker.com | sudo sh sudo usermod -aG docker $USEROn WSL2 the script prints
WSL DETECTED: We recommend using Docker Desktopand then sits still for about twenty seconds. That is a notice, not an error. Leave it running (do not press Ctrl+C) and the install carries on and completes on its own. Docker Desktop is not needed. -
Refresh your group membership
The
usermodline only takes effect in a new session, so the shell you ran it in still cannot reach Docker.Linux: log out and back in.
WSL2: run
wsl.exe --shutdown(from the Ubuntu window or PowerShell), then reopen Ubuntu from the Start menu.Mac (Multipass): type
exit, then runmultipass shell labsagain.Confirm it took effect:
docker psAn empty table is the right answer. If it reports
permission denied, the refresh has not happened yet. Either redo the step above, or runnewgrp dockeras a one-time shortcut for the current shell. -
Containerlab
bash -c "$(curl -sL https://get.containerlab.dev)"Confirm with
containerlab version. -
Pull the router image once
docker pull quay.io/frrouting/frr:10.4.5Every lab uses this same image, so this is the only download.
-
tmux and unzip
sudo apt install -y tmux unzip./labctl tabsuses tmux to open one window per router in a single command. Without tmux the labs still run, but you would be opening those terminals yourself.unzipopens the lab zips; a fresh Ubuntu, on WSL2 or in a VM, often does not have it.
Windows (WSL2)
WSL2 runs a real Linux kernel, so Docker and Containerlab behave as they do on a Linux host. Ten to twenty minutes end to end; longer the first time on a machine that has never had WSL2 or a VM.
-
Enable the Windows features
1a. Confirm virtualization is on: Task Manager, Performance, CPU. The bottom right should read "Virtualization: Enabled." If it says Disabled, enable Intel VT-x or AMD SVM in the BIOS/UEFI first; WSL2 cannot run without it.
1b. Open Start, type "Turn Windows features on or off," open it, and check both "Virtual Machine Platform" and "Windows Subsystem for Linux." Click OK and let it finish.
1c. Restart the computer. Use Restart, not Shut down; Shut down with Fast Startup does not apply feature changes. This is the only reboot needed.
-
Install Ubuntu
2a. Open PowerShell as administrator and run:
wsl --install -d UbuntuIt downloads Ubuntu and, in the same window, asks you to create a Unix username and password. Pick anything; it is separate from your Windows login.
2b. Ubuntu asks whether to opt in to metrics collection. Answer
n. It has no effect on the labs.2c. The prompt now shows a Linux path under
/mnt/c. Typecd ~to move to your Linux home folder; the prompt should end in~$. Do all later steps from here.2d. From now on, Ubuntu is in the Start menu. Open it from there for future sessions; PowerShell is not needed again.
If 2a instead prints a message about enabling a component and rebooting, Restart once more and run the command again.
-
Enable systemd
Docker runs natively under systemd. Inside Ubuntu, create
/etc/wsl.conf:sudo tee /etc/wsl.conf >/dev/null <<'EOF' [boot] systemd=true EOFThen shut WSL down so the setting takes effect. This works from the Ubuntu window or from PowerShell:
wsl.exe --shutdownIt closes the Ubuntu window. Reopen Ubuntu from the Start menu before continuing.
-
Follow the Linux steps
Inside Ubuntu, work through the five Linux steps above: Docker via get.docker.com, the group refresh, Containerlab, the FRR image pull, and tmux with unzip. The WSL2 notes in those steps are written for this track.
If you use the Windows Terminal app, setting Ubuntu as its default profile (Settings, Startup) makes new tabs open in Linux. Not required; ./labctl tabs handles multiple windows for you.
Mac (Multipass)
The labs run on Linux, so on a Mac they run inside a small Ubuntu VM that Multipass creates. Do not run the Linux track's commands on macOS itself: the Docker install script refuses macOS, and usermod does not exist there. Ten to twenty minutes end to end; longer the first time on a machine that has never had WSL2 or a VM.
-
Check your macOS version
Apple menu, About This Mac. Multipass needs macOS 13.3 or later. If yours is older, open System Settings, General, Software Update (System Preferences, Software Update on macOS 12 and earlier) and update first; the Multipass installer refuses to run on an older version.
-
Install Multipass
Download the macOS installer from multipass.run and run it. Homebrew users can install it this way instead; Homebrew is not required:
brew install --cask multipassClose and reopen Terminal afterward.
-
Create the VM
multipass launch --name labs --cpus 2 --memory 4G --disk 20GThe first run downloads Ubuntu and takes a few minutes.
-
Open a shell in it
multipass shell labsThe prompt becomes
ubuntu@labs. You are now on Linux: follow the Linux track from its step 1. For the group refresh in step 2, typeexitand runmultipass shell labsagain. -
Run multipass on the Mac, never in the VM
Every
multipasscommand runs in the Mac's own Terminal, at the prompt that shows your Mac's name, never atubuntu@labs. With the VM shell open, use a second Terminal window for them. Never putsudoin front ofmultipass: it breaks authentication with the Multipass service. -
Get a lab into the VM
The browser saves the download on the Mac, where the VM cannot see it, and Safari usually unzips it as it arrives. From a Mac Terminal (not inside the VM), see which you have:
ls ~/Downloads | grep lab-01If it shows a folder,
lab-01-area-boundary-trap, copy the folder into the VM:multipass exec labs -- mkdir -p /home/ubuntu/labs multipass transfer -r ~/Downloads/lab-01-area-boundary-trap labs:/home/ubuntu/labs/If it shows the zip,
lab-01-area-boundary-trap.zip, copy the zip into the VM:multipass transfer ~/Downloads/lab-01-area-boundary-trap.zip labs:/home/ubuntu/then unzip it inside the VM. This needs
unzip, which the Linux track's step 5 installs:mkdir -p ~/labs && mv ~/lab-01-area-boundary-trap.zip ~/labs/ && cd ~/labs && unzip lab-01-area-boundary-trap.zipEither way the lab is now in
~/labsinside the VM:cdinto its folder and run./labctl deploy, as in Run a lab. For the paid pack, grep foradjacencyand userouting-pack-1orrouting-pack-2in place oflab-01-area-boundary-trap.On UTM, share the Mac's Downloads folder with the VM and mount it inside the VM as UTM's Linux guide describes, then copy the zip from that mount.
-
Later sessions
From a Mac Terminal, start the VM if it was stopped, then open a shell in it:
multipass start labs multipass shell labsWhen you are finished, tear down any running lab with
./labctl destroy, then from a Mac Terminal:multipass stop labs
Run a lab
Every lab, free or paid, arrives as a zip. Get Lab 01 free here and the paid pack arrives by email after purchase.
Download the zip in your browser, then move it into the Linux home folder and unzip it. Pick your platform:
mkdir -p ~/labs creates the folder the first time; it's harmless afterward.
Windows (WSL2)
mkdir -p ~/labs && cp /mnt/c/Users/<your-windows-name>/Downloads/lab-01-area-boundary-trap.zip ~/labs/ && cd ~/labs && unzip lab-01-area-boundary-trap.zip
Linux
mkdir -p ~/labs && mv ~/Downloads/lab-01-area-boundary-trap.zip ~/labs/ && cd ~/labs && unzip lab-01-area-boundary-trap.zip
Mac (Multipass), first from a Mac Terminal, see whether Safari unzipped the download:
ls ~/Downloads | grep lab-01
If it shows a folder, copy the folder into the VM:
multipass exec labs -- mkdir -p /home/ubuntu/labs
multipass transfer -r ~/Downloads/lab-01-area-boundary-trap labs:/home/ubuntu/labs/
then inside the VM, cd ~/labs.
If it shows the zip, copy the zip into the VM:
multipass transfer ~/Downloads/lab-01-area-boundary-trap.zip labs:/home/ubuntu/
then inside the VM:
mkdir -p ~/labs && mv ~/lab-01-area-boundary-trap.zip ~/labs/ && cd ~/labs && unzip lab-01-area-boundary-trap.zip
Labs must live under the Linux home (~/labs), not under /mnt/c or the Mac filesystem. Windows-mounted paths carry no Unix file permissions, so labctl arrives without its executable bit and will not run, and they are markedly slower to run from. On a Mac, the containers run inside the VM and cannot see the Mac's folders at all.
Then start it:
cd lab-01-area-boundary-trap
./labctl deploy
The lab is now running. Open lab.html inside the lab folder in a browser for the topology, the symptom, the investigation questions, and the reveal for when you have a theory, then come back to the terminal to work it. It needs no network, and every lab has one. Lab 01 also has a public page, the Lab 01 page, with its topology and symptom. From WSL2, explorer.exe . opens the lab folder in Windows; on a Mac, multipass transfer the lab.html back out, or read scenario.md in the terminal.
If ./labctl reports Permission denied, run chmod +x labctl once. Some Windows unzip tools drop the executable bit, and a copy through /mnt/c always does.
Each lab folder has the same launcher with the same commands:
./labctl deploy # bring it up and apply the scenario
./labctl tabs # open a window per router in tmux
./labctl status # neighbor state and routes at a glance
./labctl sh r2 # a Linux shell on that router
./labctl verify # check your fix
./labctl reset # back to the broken starting state
./labctl destroy # tear it down
Paid pack
The pack arrives the same way as the free lab, as a download link in the Gumroad email. Copy it into ~/labs and unzip it exactly as above, with the pack's zip name. It unzips to one folder holding all ten labs; cd into any of them and run ./labctl deploy. Every lab inside it uses the same ./labctl commands shown above.
Working the lab
Every lab is easier with one terminal per router, and one more in the lab folder for the launcher. ./labctl tabs lays that out in one command:
./labctl tabs
It opens a tmux session named after the lab: one window per router, each already inside that router's vtysh, and a last window named ctl in the lab folder for status, verify and reveal. Run it again at any point and it reattaches to the session you left rather than building a second one.
The bar along the bottom lists the windows (1:r1* 2:r2 3:r3 4:ctl), and the asterisk marks the one you're in. To switch, press Ctrl+B, release both keys, then press the key that follows it:
Ctrl+B, then 2 switch to r2 (any window number works)
Ctrl+B, then n / p next / previous window
Ctrl+B, then w pick a window from a list
Ctrl+B, then d detach, leaving the lab running
./labctl tabs reattaches to the session you left.
Detaching leaves every router where you left it, so you can close the terminal, come back later, and pick the same session up mid-investigation. The point of the layout is to keep the router where the symptom shows in a window of its own, so you can re-run a command there without losing whatever you are reading on another router.
The session belongs to the lab, and ./labctl destroy closes it along with the containers. Run destroy from the ctl window and it leaves the session standing, since that is the shell you are typing in; detach first, or close it afterwards with tmux kill-session -t <lab-name>. If a session is ever left behind without its routers, ./labctl tabs rebuilds it rather than dropping you into the remains.
Each lab's scenario.md names the windows that topology needs. The same folder also has lab.html (the scenario with its diagram, readable in a browser with no network), and ./labctl reveal prints the concept and the fix once you have a theory.
Working in vtysh
FRR's shell is modeled on IOS. Get into a router with:
docker exec -it clab-<lab-name>-r1 vtysh
Many familiar operational commands work much as you'd expect:
show ip route
show ip ospf neighbor
show ip ospf database
show ip bgp summary
show running-config
configure terminal
The differences you'll notice: interfaces are named eth1, eth2 rather than GigabitEthernet; prefixes use CIDR (10.0.0.0/24) rather than wildcard masks; and in BGP, neighbors are activated under address-family ipv4 unicast. That's about the whole list for OSPF and BGP work.
The Linux side of the router
One structural difference is worth knowing before it surprises you. On a traditional platform the router owns the whole box. FRR is a routing daemon running on Linux, so the protocol is one layer and the platform is another: anything OSPF or BGP configures lives in vtysh, while properties the kernel owns (interface MTU is the one the labs run into) are reported by vtysh but changed outside it. That split is not a quirk of these labs; it is how white-box switches, SONiC and cloud routers all work.
The launcher opens that shell for you, so there is no container name to remember:
./labctl sh r2
ip, ping, ss and vtysh are all on the PATH there, and exit brings you back to the lab folder. Where a lab's fix needs it, ./labctl reveal says so and spells out the command.
If something's off
- Permission denied on Docker: you haven't re-logged in after the
usermodstep. - "OSPF did not converge" from the launcher: run
./labctl status; usually the image is still starting. Run./labctl reset. - Containers from a previous lab still around:
sudo containerlab destroy --allcleans everything. ./labctl tabsopens with no router windows, justctl: a tmux session from an earlier run outlived the lab it was built for. Each router window is a connection into a container, so destroying the lab closes them and leaves thectlshell behind. Current labs rebuild the session for you; on an older copy, close it withtmux kill-session -t <lab-name>and run./labctl tabsagain.tmux lslists what is open, and insideCtrl+B sgives the same list, wherexthenycloses the highlighted one.multipass: command not foundon a Mac: you are inside the VM. Switch to the Mac Terminal window, the one whose prompt shows your Mac's name, and run it there.- "The client is not authenticated with the Multipass service": the command was run with
sudo. Run it again withoutsudo.